首页
学习
活动
专区
工具
TVP
发布
社区首页 >问答首页 >在ASP.NET MVC3中,我应该在哪里附加自定义用户上下文会话包装器?

在ASP.NET MVC3中,我应该在哪里附加自定义用户上下文会话包装器?
EN

Stack Overflow用户
提问于 2011-02-21 07:17:44
回答 2查看 5.2K关注 0票数 16

我已经阅读了许多关于MVC中会话范围数据的文章,但我仍然不清楚在哪里可以将自定义会话包装器包含到解决方案中。

我想从IPrincipal中获取当前用户的用户名,加载有关该用户的附加信息,并将其存储在会话中。然后,我想从、控制器和视图访问该用户数据。

以下方法似乎都不适合我想要做的事情。

选项1:直接访问会话集合

似乎每个人都同意this is a bad idea,但老实说,它似乎是最简单的工作方式。但是,它不会使用户对视图可用。

代码语言:javascript
复制
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:将会话注入类构造函数 forum post

这个选项似乎很好,但我仍然不确定如何将其附加到控制器和视图。我可以在控制器中新建它,但它不应该作为依赖项被注入吗?

代码语言:javascript
复制
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类

布拉德·威尔逊在他的presentation中介绍了他的StatefulStorage课程。它是一组聪明而有用的类,其中包括接口并使用构造函数注入。然而,它似乎将我引向与选项2相同的道路。它使用接口,但我不能使用Container来注入它,因为它依赖于静态工厂。即使我可以注入它,它是如何传递到视图的。是否每个用户都必须有一个具有可设置ViewModel属性的基类?

选项4:使用与 类似的方法

我可以将用户作为参数添加到操作方法中,并使用ModelBinder从会话中对其进行消减。在需要的地方添加它似乎有很大的开销。另外,我仍然需要将其添加到ViewModel中,才能使其对视图可用。

代码语言:javascript
复制
public ActionResult Edit(int id, 
   [ModelBinder(typeof(IPrincipalModelBinder))] IPrincipal user)
{ ... }

我觉得我想得太多了,但似乎也应该有一个明显的地方来做这类事情。我遗漏了什么?

EN

回答 2

Stack Overflow用户

回答已采纳

发布于 2011-02-21 08:11:10

我的会话方法:

带有接口的封面会话:

代码语言:javascript
复制
public interface ISessionWrapper
{
    int SomeInteger { get; set; }
}

使用HttpContext.Current.Session实现接口:

代码语言:javascript
复制
public class HttpContextSessionWrapper : ISessionWrapper
{
    private T GetFromSession<T>(string key)
    {
        return (T) HttpContext.Current.Session[key];
    }

    private void SetInSession(string key, object value)
    {
        HttpContext.Current.Session[key] = value;
    }

    public int SomeInteger
    {
        get { return GetFromSession<int>("SomeInteger"); }
        set { SetInSession("SomeInteger", value); }
    }
}

注入到控制器中:

代码语言:javascript
复制
public class BaseController : Controller
{
    public ISessionWrapper SessionWrapper { get; set; }

    public BaseController(ISessionWrapper sessionWrapper)
    {
        SessionWrapper = sessionWrapper;
    }
}

对象依赖:

代码语言:javascript
复制
Bind<ISessionWrapper>().To<HttpContextSessionWrapper>()

当你想在母版页中使用ViewData和在特定视图中使用视图模型时,可以使用它来传递一些常用的信息。

票数 13
EN

Stack Overflow用户

发布于 2011-02-21 07:27:57

我强烈建议您通过控制器向下传递视图中需要的任何内容。这样,视图应该呈现哪些数据的决定权就落在了控制器身上。为了尽可能简单,创建一个具有可设置User属性的抽象ViewModelWithUserBase类确实不是一个坏主意。一种选择是创建一个接口IViewModelWithUser,并每次重新实现User属性(或者与基类结合,但如果在某些特殊情况下这会使事情变得更容易,则可以选择重新实现而不是继承基类)。

就填充此属性而言,使用操作筛选器可能很容易完成。使用OnActionExecuted方法,您可以测试传递给视图的模型是否实现了您的基类(或接口),然后在适当的情况下用正确的IPrincipal对象填充属性。这样做的好处是,由于操作筛选器不会在单元测试中执行,因此您可以在操作筛选器中使用选项1中的依赖于HttpContext.Current.Session的代码,并且在控制器上仍然有一个可测试的接口。

票数 3
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/5060804

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档