2010-10-19 10 views
22

preguntas similares han sido hechas antes, pero no exactamente lo mismo (a menos que me lo perdí)Cómo pasar información del usuario actual a todas las capas de DDD

quiero pasar instancia de clase IUserInfo a través de mi servicio, dominio, Eventos de dominio , Controladores de eventos de dominio ...

¿Cuál es la mejor manera de hacerlo?

¿Debo

  • inyectarlo utilizando IoC registrándolo contra instancia de Httpcontext.Current.session [ "CurrentUser"];

  • Agregue los datos al hilo actual.

  • Cualquier otra forma

estoy atascado en el dominio controladores de eventos donde quiero utilizar los datos de auditoría, así como el envío de mensajes de correo electrónico.

Quiero ser capaz de utilizar la información del Usuario Actual desde casi cualquier lugar de mi aplicación.

Con subprocesos, ya que los hilos se agrupan, soy escéptico si la reutilización de subprocesos restablecerá los datos. Si no, por favor comprame cómo usar el enhebrado para pasar la instancia de IUser.

Saludos,

Mar

+0

Solo quería señalar que hay una pequeña superposición con mi pregunta que he preguntado más recientemente sobre permitir que los repositorios conozcan el contexto del usuario. He intentado resolver este problema junto con el uso del contexto del usuario para acceder a otros valores sensibles al contexto del usuario. http://stackoverflow.com/questions/5374176/can-ddd-repositories-be-aware-of-user-context – jpierson

Respuesta

5

he hecho este tipo de cosas antes de utilizar COI. El beneficio de esto es que es muy comprobable, puede anular la información de usuario para las pruebas, y es razonablemente legible y fácil de seguir.

+0

Gracias. Esperaré un día más para ver si alguien más tiene otras ideas. Para la forma de IoC, ¿la estaba almacenando en Httpcontext.Current.session ["CurrentUser"] primero? – TheMar

+1

No lo almacenaría en la sesión, sino en HttpContext.Items. La sesión persiste, pero HttpContext.Items existe solo durante la vigencia de la solicitud, por lo que es perfecta para cosas como esta. – hackerhasid

+5

Probablemente he malinterpretado algo, pero ¿cómo se puede acceder a HttpContext desde todas las capas, cuando, por ejemplo, el dominio no debe saber nada sobre HttpContext? – vorou

16

Mi enfoque puede no ser ideal, pero creo que funciona bastante bien. Cosa que hice - Decidí no usar la inyección de dependencia pasar al usuario actual en todas partes directamente porque eso se volvía demasiado engorroso y cambiaba al contexto estático. Problema con contextos: son un poco difíciles de manejar.

Ésta se define en mi dominio:

public static class UserContext{ 
    private static Func<User> _getCurrentUser; 
    private static bool _initialized; 
    public static User Current{ 
    get{ 
     if(!_initialized) 
     throw new Exception("Can i haz getCurrentUser delegate?"); 
     var user=_getCurrentUser(); 
     return user??User.Anonymous; 
    } 
    } 
    public static void Initialize(Func<User> getCurrentUser){ 
    _getCurrentUser=getCurrentUser; 
    _initialized=true; 
    } 
} 

Nota que el delegado es estática - para la aplicación conjunto sólo uno a la vez. Y no estoy 100% seguro de su ciclo de vida, posibles fugas de memoria o lo que sea.

La aplicación de cliente es responsable de inicializar el contexto. Mi aplicación web hace que en cada petición:

public class UserContextTask:BootstrapperTask{ 
private readonly IUserSession _userSession; 
public UserContextTask(IUserSession userSession){ 
    Guard.AgainstNull(userSession); 
    _userSession=userSession; 
} 
public override TaskContinuation Execute(){ 
    UserContext.Initialize(()=>_userSession.GetCurrentUser()); 
    return TaskContinuation.Continue; 
} 
} 

Usando mvcextensions biblioteca de tareas bootstrapping corriente de línea. Solo puede suscribirse para acordar eventos en global.asax para eso.

En el lado del cliente (aplicación web), que implementan servicios de aplicaciones nombrado IUserSession:

public User GetCurrentUser(){ 
    if(HttpContext.Current.User==null) return null; 
    var identity=HttpContext.Current.User.Identity; 
    if(!identity.IsAuthenticated) return null; 
    var user=_repository.ByUserName(identity.Name); 
    if(user==null) throw new Exception("User not found. It should be. Looks bad."); 
    return user; 
} 

Hay algunos más lame code necesaria con el fin de utilizar formularios de autenticación con funciones w/o proveedor de proveedor de pertenencia y el papel. Pero ese no es el punto de esta pregunta.

A nivel de dominio - que estoy describiendo explícitamente permisos que los usuarios podrían tener como éste:

public class AcceptApplications:IUserRights{ 
    public bool IsSatisfiedBy(User u){ 
    return u.IsInAnyRole(Role.JTS,Role.Secretary); 
    } 
    public void CheckRightsFor(User u){ 
    if(!IsSatisfiedBy(u)) throw new ApplicationException 
     ("User is not authorized to accept applications."); 
    } 
} 

Lo interesante es - esos permisos se pueden hacer más sofisticado. Por ejemplo:

public class FillQualityAssessment:IUserRights{ 
    private readonly Application _application; 
    public FillQualityAssessment(Application application){ 
    Guard.AgainstNull(application, 
     "User rights check failed. Application not specified."); 
    _application=application; 
    } 
    public bool IsSatisfiedBy(User u){ 
    return u.IsInRole(Role.Assessor)&&_application.Assessors.Contains(u); 
    } 
    public void CheckRightsFor(User u){ 
    if(!IsSatisfiedBy(u)) 
     throw new ApplicationException 
     ("User is not authorized to fill quality assessment."); 
    } 
    } 

permisos se puede comprobar vica versa también - El usuario tiene estos muchachos:

public virtual bool HasRightsTo<T>(T authorizationSpec) where T:IUserRights{ 
    return authorizationSpec.IsSatisfiedBy(this); 
} 
public virtual void CheckRightsFor<T>(T authorizationSpec) where T:IUserRights{ 
    authorizationSpec.CheckRightsFor(this); 
} 

Aquí está mi agregada clase base de la raíz:

public class Root:Entity,IRoot{ 
    public virtual void Authorize(IUserRights rights){ 
    UserContext.Current.CheckRightsFor(rights); 
    } 
} 

Y aquí es cómo comprobar los permisos:

public class Application{ 
    public virtual void Accept(){ 
    Authorize(new AcceptApplications()); 
    OpeningStatus=OpeningStatus.Accepted; 
    } 
} 

Espero que ayude ...

+1

@ Arnis- Gracias por el ejemplo detallado.Mirando el código, estoy un poco inclinado hacia la forma de IoC para la preocupación de legibilidad y no tengo que pensar en mantener la clase estática. Todavía voy a intentarlo y ver en acción. – TheMar

+0

Creo que esto podría simplificarse un poco, pero aún así sufriría dependencia de HttpContext, lo que significa que no es muy comprobable. Al usar IoC, puede usar HttpContext para el sitio web, pero puede pasar lo que desee para probarlo. OMI esto es una gran ventaja. – hackerhasid

+0

@statichippo hay inversión de control en mi ejemplo. pasar el delegado a la función 'Initialize' es IoC. El contexto en sí no sabe cómo se va a poner al usuario actual. La implementación de UserSession se ubica en la aplicación web, el dominio está libre de preocupaciones técnicas. Es comprobable, solo necesito inicializarlo con lo que necesito. Lo único malo es que es estático y no puedo ver desde arriba si algo usará UserContext. –

Cuestiones relacionadas