我发现几乎每个类(控制器、视图、HTML 助手、服务等)都需要当前登录的用户数据。所以我考虑创建一个“环境上下文”而不是直接注入 IUserService 或用户。
我的方法看起来像这样。
public class Bootstrapper
{
public void Boot()
{
var container = new Container();
// the call to IUserService.GetUser is cached per Http request
// by using a dynamic proxy caching mechanism, that also handles cases where we want to
// invalidate a cache within an Http request
UserContext.ConfigureUser = container.GetInstance<IUserService>().GetUser;
}
}
public interface IUserService
{
User GetUser();
}
public class User
{
string Name { get; set; }
}
public class UserContext : AbstractFactoryBase<User>
{
public static Func<User> ConfigureUser = NotConfigured;
public static User ActiveUser { get { return ConfigureUser(); } }
}
public class AbstractFactoryBase<T>
{
protected static T NotConfigured()
{
throw new Exception(String.Format("{0} is not configured", typeof(T).Name));
}
}
示例用法:
public class Controller
{
public ActionResult Index()
{
var activeUser = UserContext.ActiveUser;
return View();
}
}
我的方法是正确的还是我遗漏了什么?您有更好的解决方案吗?
更新:
用户类的更多细节:
public class User
{
string Name { get; set; }
bool IsSuperUser { get; set;}
IEnumerable<AzManOperation> Operations { get; set}
}
在控制器中,我们需要检查用户是否是超级用户,以便只为超级用户提供一些额外的功能。
public class BaseController : Controller
{
private readonly IUserService _userService;
BaseControler(IUserService userService)
{
_userService = userService
}
public User ActiveUser
{
get { return _userService.GetUser(); }
}
}
在视图中,我们检查操作以仅在用户有权这样做时显示编辑或删除按钮。视图从不使用 DependencyResolver,而是使用 ViewBag 或 ViewModel。我的想法是实现一个自定义 ViewBasePage 并提供一个 ActiveUser 属性,以便视图可以轻松访问。
在HtmlHelpers中,我们根据 IsSuperUser 和 Operations 渲染控件(传入 User 对象或使用 DependencyResolver)。
在服务类中,我们也需要这些属性。例如,决定一个购物篮是否有效(检查是否允许用户购买不在标准列表中的物品)。所以 Service 类依赖IUserService
并调用GetUser()
.
在Action Filters中强制用户更改他的密码(仅当它不是 SuperUser 并且 User.ForcePasswordChange 为 true 时)。这里我们使用 DependencyResolver。
我希望有一种更简单的方法来获取 User 对象,而不是使用 DependencyResolver.Current.GetService().GetUser() 或使用ViewBag.ActiveUser = User
. 用户对象是一个几乎无处不在需要检查权限等的对象。