Как передать текущую информацию пользователя всем слоям в DDD - PullRequest
22 голосов
/ 19 октября 2010

Подобные вопросы задавались ранее, но не совсем так (если я не пропустил)

Я хочу передать экземпляр класса IUserInfo через мой Сервис, Домен, События домена, Обработчики событий домена ...

Что является лучшим способом сделать это.

Должен ли я

  • Внедрить его с помощью IoC, зарегистрировав его в экземпляре Httpcontext.Current.session ["CurrentUser"];

  • Добавить данные в текущую тему.

  • Любым другим способом

Я застрял наОбработчики событий домена, в которых я хочу использовать данные для аудита, а также для отправки электронных писем.

Я хочу иметь возможность использовать информацию CurrentUser практически из любого места в моем приложении.

С многопоточностью какпотоки объединяются Я скептически отношусь к тому, что повторное использование потоков приведет к сбросу данных.Если нет, пожалуйста, напишите мне, как использовать многопоточность для передачи экземпляра IUser.

С уважением,

Март

Ответы [ 2 ]

16 голосов
/ 19 октября 2010

Мой подход может быть не идеальным, но я считаю, что он работает довольно хорошо.Что я и сделал - я решил не использовать внедрение зависимостей передавать текущего пользователя везде напрямую, потому что это становилось слишком громоздким и переключалось на статический контекст.Проблема с контекстами - ими немного сложно управлять.

Это определено в моем домене:

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

Обратите внимание, что делегат статичен - для всего приложения только по одному за раз.И я не на 100% уверен в его жизненном цикле, возможных утечках памяти или еще чем-то подобном.

Клиентское приложение отвечает за инициализацию контекста.Мое веб-приложение делает это при каждом запросе:

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

Использование библиотеки mvcextensions для оптимизации задач начальной загрузки.Вы можете просто подписаться на соответствующие события в global.asax для этого.

На стороне клиента (веб-приложение) я реализую службу приложений с именем 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;
}

Для использования аутентификации форм с ролями без поставщика членства и поставщика ролей требуется еще код lame .Но суть этого вопроса не в этом.

На уровне домена - я подробно описываю разрешения, которые могут иметь пользователи, например:

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

Классная вещь - эти разрешения могут бытьсделал более изощренным.Например:

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

Разрешения могут быть проверены и наоборот - у пользователя есть следующие пароли:

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

Вот мой совокупный корневой базовый класс:

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

Ивот как я проверяю права доступа:

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

Надеюсь, это поможет ...

5 голосов
/ 19 октября 2010

Я делал подобные вещи перед использованием IoC.Преимущество этого заключается в том, что он очень тестируемый - вы можете опубликовать информацию о пользователе для тестирования - и достаточно читабельный и понятный.

...