我有一个基本控制器,在每次加载页面之前,我想获得当前用户。我最初在我的BaseController
中有一个看起来像这样的构造函数
public BaseController(ISystemUserCommand command)
{
_systemUserCommand = command
}
这样做的问题是,每个继承自BaseController
的控制器都必须在其构造函数中包含ISystemUserCommand
,我认为这不会很好。
相反,我试图只创建一个服务类的实例(如下所示 - 它是var sid下的注释行...)但是我需要传递用户服务。我如何在这里传递用户服务,或者这是一种不好的方式吗?
public abstract class BaseController : Controller
{
public SystemUserViewModel CurrentUser { get; set; }
private readonly ISystemUserCommand _systemUserCommand;
public SystemUserViewModel GetCurrentUser()
{
if (HttpContext == null || HttpContext.User == null) return null;
if (CurrentUser != null) return CurrentUser;
var sid = System.Web.HttpContext.Current.Request.LogonUserIdentity.User.ToString();
//var command = new SystemUserCommand();
CurrentUser = _systemUserCommand.GetUser(sid);
return CurrentUser;
}
public void SetUserInformation(SystemUserViewModel currentUser)
{
ViewBag.UserId = currentUser.SystemUserId;
ViewBag.FullName = string.Format("{0} {1}", currentUser.FirstName, currentUser.LastName);
ViewBag.FirstName = currentUser.FirstName;
ViewBag.LastName = currentUser.LastName;
ViewBag.CurrentUser = currentUser;
}
protected override void OnActionExecuting(ActionExecutingContext filterContext)
{
var currentUser = GetCurrentUser();
if (currentUser != null)
{
if (currentUser.IsActive)
{
SetUserInformation(currentUser);
}
else
filterContext.Result = RedirectToAction("denied", "unauthorized");
}
else
filterContext.Result = RedirectToAction("denied", "unauthorized");
base.OnActionExecuting(filterContext);
}
}
public class SystemUserCommand : ISystemUserCommand
{
private readonly ISystemUserBusiness _systemUserBusiness;
public SystemUserCommand(ISystemUserBusiness systemUserBusiness)
{
_systemUserBusiness = systemUserBusiness;
}
...
}
答案 0 :(得分:2)
您可以通过基类使用属性注入而不是构造函数注入,例如使用unity:
public abstract class BaseController : Controller
{
[Dependency]
public ISystemUserCommand SystemUserCommand { get; set; }
}
这意味着接口引用仅在基类上。
有关完整示例,请参阅here。
编辑,Autofac示例:
您不需要依赖项的属性属性
public abstract class BaseController : Controller
{
public ISystemUserCommand SystemUserCommand { get; set; }
}
只需在autofac构建器上注册要自动解析的属性:
builder.RegisterControllers(typeof(MvcApplication).Assembly).Where(t => t.IsAssignableFrom(typeof(BaseController))).PropertiesAutowired();
请参阅autofac属性注入here。
答案 1 :(得分:1)
首先,在控制器中覆盖OnActionExecuting
似乎不太好。您可以使用专门为此目的而设计的过滤器。这似乎是你创建BaseController
的主要原因。
关于在所有必需的服务中注入系统命令的问题,我会这样做,但是没有从基类继承,因为我通常更喜欢聚合到继承。这意味着需要使用该服务的每个控制器都能获得它。
我用了几次抽象一些操作的另一个选项是创建一个UserSerivce
,它将为控制器提供所需的操作。它将注入ISystemUserCommand
和HttpContext,这样你的所有控制器都不必完成这项工作。如果需要可测试性,可以将HttpContext.Current用作静态,也可以将其抽象出来。
此外,我不建议使用属性注入,因为它比构造函数注入更加模糊,如果可能的话应该首选。
您可以阅读有关过滤器here的更多信息。不幸的是,如果你使用过滤器,那么注入过滤器本身并不容易,而且主要使用属性注入或ServiceLocator模式(通常不好)。虽然有一些伏都教可以做得更好。我认为SimpleInjector有很多关于如何将DI应用到MVC中的过滤器的示例和教程,也许他们现在甚至可以使用nuget包来解决这个问题。