创建带有依赖注入的接口实例

本文关键字:接口 实例 注入 依赖 创建 | 更新日期: 2023-09-27 18:15:22

我有一个基本控制器,在每次页面加载之前,我想获得当前用户。我最初在BaseController中有一个构造函数,看起来像这样

public BaseController(ISystemUserCommand command)
{
    _systemUserCommand = command
}

这样做的问题是,从BaseController继承的每个控制器都必须在其构造函数中包含ISystemUserCommand,我认为这不是很好。

相反,我试图创建服务类的一个实例(如下所示-它是var下的注释行…),但我需要传入user service。我该如何传递用户服务呢,这样做不好吗?

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;
    }
    ...
}

创建带有依赖注入的接口实例

你可以通过基类使用属性注入而不是构造函数注入,例如使用unity:

public abstract class BaseController : Controller
{
    [Dependency]
    public ISystemUserCommand SystemUserCommand { get; set; }
}

这将意味着接口引用仅在基类上。

查看完整的示例。

编辑,autoface示例:

你不需要依赖的属性,

public abstract class BaseController : Controller
{
    public ISystemUserCommand SystemUserCommand { get; set; }
}

将属性注册为autofac生成器上的自动解析:

builder.RegisterControllers(typeof(MvcApplication).Assembly).Where(t => t.IsAssignableFrom(typeof(BaseController))).PropertiesAutowired();

首先,在控制器中覆盖OnActionExecuting似乎不是一个好主意。您可以使用专门为此目的设计的过滤器。这似乎是你创建BaseController的主要原因。

关于在所有必需的服务中注入系统命令的问题,我会这样做,但不会从基类继承,因为我通常更喜欢聚合而不是继承。这意味着每个需要使用该服务的控制器都会得到它。

我使用过几次抽象一些操作的另一个选项是创建一个UserSerivce,它将向控制器提供所需的操作。它将有ISystemUserCommand和HttpContext注入内部,这样你所有的控制器都不必做这项工作。你可以使用HttpContext。电流是静态的,或者如果你需要可测试性,把它抽象掉。

此外,我不推荐属性注入,因为它比构造函数注入更晦涩,如果可能的话,应该首选构造函数注入。

你可以在这里阅读更多关于过滤器的信息。不幸的是,如果你使用过滤器,那么注入过滤器本身就不那么容易了,大多数情况下是通过属性注入或ServiceLocator模式来完成的(这通常不是很好)。不过用一些巫术还是有可能做得更好的。我认为SimpleInjector有很多关于如何将DI应用于MVC中的过滤器的示例和教程,也许他们现在甚至有一个nuget包来实现这一点。