Cómo pasar información actual del usuario a todas las capas en DDD

Se han hecho preguntas similares antes, pero no del todo (a menos que me lo haya perdido)

Deseo pasar la instancia de la 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?

Debería

  • Inyectarlo utilizando IoC registrándolo contra la instancia de Httpcontext.Current.session [“CurrentUser”];

  • Agregue los datos al hilo actual.

  • Cualquier otra manera

Estoy atascado en Domain Event Handlers, donde quiero usar los datos para auditar y enviar correos electrónicos.

Quiero poder usar la información del Usuario Actual desde casi cualquier lugar de mi aplicación.

Con el subprocesamiento a medida que los subprocesos se combinan, 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

He hecho este tipo de cosas antes de usar IoC. 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.

Mi enfoque puede no ser ideal, pero creo que funciona bastante bien. Cosa que hice – Decidí no usar el usuario actual de la inyección de la inyección de la dependencia 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.

Este está definido en mi dominio:

public static class UserContext{ private static Func _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 getCurrentUser){ _getCurrentUser=getCurrentUser; _initialized=true; } } 

Tenga en cuenta que el delegado es estático, para toda la aplicación, solo de a uno por vez. Y no estoy 100% seguro de su ciclo de vida, posibles memory leaks o lo que sea.

La aplicación del cliente es responsable de inicializar el contexto. Mi aplicación web lo hace en cada solicitud:

 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; } } 

Uso de la biblioteca mvcextensions para realizar una secuencia de tareas de arranque. Solo puede suscribirse para acordar eventos en global.asax para eso.

En el lado del cliente (aplicación web), implemento el servicio de aplicaciones llamado 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 un código cojo más necesario para usar Auth de formularios con roles sin proveedor de membresía y proveedor de roles. Pero ese no es el punto de esta pregunta.

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

 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 bueno es que esos permisos pueden hacerse más sofisticados. P.ej:

 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."); } } 

Los permisos también se pueden revisar vica versa – El usuario tiene estos tipos:

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

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

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

Y así es como compruebo los permisos:

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

Espero que eso ayude…