Я прочитал много сообщений о данных с привязкой к сеансу в MVC, но мне все еще неясно, где лучше всего включить пользовательскую оболочку сеанса в решение.
Я хочу получить имя пользователя текущего пользователя из IPrincipal, загрузить дополнительную информацию об этом пользователе и сохранить ее в сеансе. Затем я хочу получить доступ к этим данным пользователя из Контроллера и Представления .
Ни один из следующих подходов не подходит для того, что я хочу сделать.
Вариант 1: Доступ к коллекции сеансов напрямую
Кажется, все согласны , что это плохая идея , но, честно говоря, это самая простая вещь, которая работает. Однако он не делает пользователя доступным для представления.
public class ControllerBase : Controller {
public ControllerBase() : this(new UserRepository()) {}
public ControllerBase(IUserRepository userRepository) {
_userRepository = userRepository;
}
protected IUserRepository _userRepository = null;
protected const string _userSessionKey = "ControllerBase_UserSessionKey";
protected User {
get {
var user = HttpContext.Current.Session[_userSessionKey] as User;
if (user == null) {
var principal = this.HttpContext.User;
if (principal != null) {
user = _userRepository.LoadByName(principal.Identity.Name);
HttpContext.Current.Session[_userSessionKey] = user;
}
}
return user;
}
}
}
Вариант 2: Внедрение сеанса в конструктор класса сообщение на форуме
Этот вариант кажется довольно хорошим, но я все еще не уверен, как прикрепить это к контроллеру и представлению. Я мог бы добавить что-то новое в Контроллер, но разве не следует вводить его как зависимость?
public class UserContext {
public UserContext()
: this(new HttpSessionStateWrapper(HttpContext.Current.Session),
new UserRepository()) { }
public UserContext(HttpSessionStateBase sessionWrapper, IUserRepository userRepository) {
Session = sessionWrapper;
UserRepository = userRepository;
}
private HttpSessionStateBase Session { get; set; }
private IUserRepository UserRepository{ get; set; }
public User Current {
get {
//see same code as option one
}
}
}
Вариант 3: Используйте класс StatefulStorage Брэда Уилсона
В его презентации Брэд Уилсон описывает свое StatefulStorage учебный класс. Это умный и полезный набор классов, которые включают интерфейсы и используют внедрение конструктора. Однако, похоже, он ведет меня по тому же пути, что и вариант 2. Он использует интерфейсы, но я не мог ' t использовать Контейнер для его внедрения, потому что он полагается на статическую фабрику. Даже если бы я мог ввести его, как он передается в представление. Должна ли каждая ViewModel иметь базовый класс с настраиваемым свойством User?
Вариант 4: Используйте что-то похожее на Hanselman IPrincipal ModelBinder
Я мог бы добавить пользователя в качестве параметра к методу Action и использовать ModelBinder, чтобы увлажнить его из сеанса. Похоже, что добавлять его везде, где это необходимо, слишком дорого. Кроме того, мне все равно придется добавить его в ViewModel, чтобы сделать его доступным для View.
public ActionResult Edit(int id,
[ModelBinder(typeof(IPrincipalModelBinder))] IPrincipal user)
{ ... }
Я чувствую, что слишком много думаю об этом, но также кажется, что должно быть очевидное место для таких вещей. Что мне не хватает?