Roo*_*ian 11 c# asp.net asp.net-mvc dependency-injection ambientcontext
我发现几乎每个类(控制器,视图,HTML帮助程序,服务等)都需要当前登录的用户数据.所以我想创建一个"Ambient Context"而不是直接注入IUserService或User.
我的方法看起来像那样.
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));
}
}
Run Code Online (Sandbox Code Playgroud)
用法示例:
public class Controller
{
public ActionResult Index()
{
var activeUser = UserContext.ActiveUser;
return View();
}
}
Run Code Online (Sandbox Code Playgroud)
我的方法是正确的还是我错过了什么?你有更好的解决方案吗?
更新:
用户类的更多细节:
public class User
{
string Name { get; set; }
bool IsSuperUser { get; set;}
IEnumerable<AzManOperation> Operations { get; set}
}
Run Code Online (Sandbox Code Playgroud)
在控制器中,我们需要检查用户是否是SuperUser才能为SuperUser提供一些额外的功能.
public class BaseController : Controller
{
private readonly IUserService _userService;
BaseControler(IUserService userService)
{
_userService = userService
}
public User ActiveUser
{
get { return _userService.GetUser(); }
}
}
Run Code Online (Sandbox Code Playgroud)
在视图中,如果用户有权这样做,我们会检查操作以仅显示编辑或删除按钮.视图从不使用DependencyResolver,而是使用ViewBag或ViewModel.我的想法是实现自定义ViewBasePage并提供ActiveUser属性,以便Views可以轻松访问.
在HtmlHelpers中,我们根据IsSuperUser和Operations渲染控件(传入User对象或使用DependencyResolver).
在服务类中,我们也需要这些属性.例如,判断篮子是否有效(检查用户是否被允许购买不在标准列表中的文章).所以Service类依赖于IUserService并调用GetUser().
在Action Filters中强制用户更改其密码(仅当它不是SuperUser并且User.ForcePasswordChange为true时).这里我们使用DependencyResolver.
我希望有一种更简单的方法来获取User对象,而不是使用DependencyResolver.Current.GetService().GetUser()或使用类似的东西ViewBag.ActiveUser = User.User对象是几乎到处检查权限等所需的对象.
在视图中,如果用户有权这样做,我们会检查操作以仅显示编辑或删除按钮.
视图不应该执行此检查.Controller应该将视图模型返回到包含布尔属性的视图,该属性指出这些按钮是否应该可见.返回一个bool IsSuperUser已经移动到视图中的众所周知.视图不应该知道它应该为超级用户显示某个按钮:这取决于控制器.应该只告知视图要显示的内容.
如果几乎所有视图都有此代码,则有一些方法可以从视图中提取重复的部分,例如使用部分视图.如果您发现自己在许多视图模型上重复这些属性,也许您应该定义一个包络视图模型(包装特定模型的通用视图模型T).控制器可以创建其视图模型,同时创建服务或横切关注点,将其包装在信封中.
在服务类中,我们也需要这些属性.例如,判断篮子是否有效
在这种情况下,您谈论的是验证,这是一个跨领域的问题.您应该使用装饰器来添加此行为.