C# 使用依赖项注入创建接口实例

C# 使用依赖项注入创建接口实例,c#,dependency-injection,asp.net-mvc-5,C#,Dependency Injection,Asp.net Mvc 5,我有一个基本控制器,在每次加载页面之前,我都希望获得当前用户。我最初在我的BaseController中有一个构造函数,看起来像这样 public BaseController(ISystemUserCommand command) { _systemUserCommand = command } 这样做的问题是,从BaseController继承的每个控制器都必须在其构造函数中包含ISystemUserCommand,我认为这不好 相反,我尝试只创建服务类的一个实例(如下所示-它是v

我有一个基本控制器,在每次加载页面之前,我都希望获得当前用户。我最初在我的
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;
    }

    ...
}

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

public abstract class BaseController : Controller
{
    [Dependency]
    public ISystemUserCommand SystemUserCommand { get; set; }
}
这意味着接口引用仅在基类上

有关完整示例,请参见

编辑,自动传真示例:

依赖项上不需要属性属性

public abstract class BaseController : Controller
{
    public ISystemUserCommand SystemUserCommand { get; set; }
}
只需在autofac builder上注册要自动解析的属性:

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

请参阅autofac属性注入。

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

public abstract class BaseController : Controller
{
    [Dependency]
    public ISystemUserCommand SystemUserCommand { get; set; }
}
这意味着接口引用仅在基类上

有关完整示例,请参见

编辑,自动传真示例:

依赖项上不需要属性属性

public abstract class BaseController : Controller
{
    public ISystemUserCommand SystemUserCommand { get; set; }
}
只需在autofac builder上注册要自动解析的属性:

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

请参阅autofac属性注入。

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

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

我曾多次使用的另一个抽象某些操作的选项是创建一个
UserSerivce
,它将向控制器提供所需的操作。它将在内部注入
ISystemUserCommand
和HttpContext,以便所有控制器都不必执行此任务。您可以使用HttpContext.Current作为静态的,也可以在需要可测试性时将其抽象掉

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


您可以阅读有关过滤器的更多信息。不幸的是,如果您使用过滤器,那么注入过滤器本身并不是那么容易,而且大部分都是通过属性注入或ServiceLocator模式来完成的(这通常并不好)。不过,使用一定量的伏都教可能会做得更好。我认为SimpleInjector有很多关于如何在MVC中将DI应用于过滤器的示例和教程,也许他们现在甚至有一个nuget包来实现这一点。

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

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

我曾多次使用的另一个抽象某些操作的选项是创建一个
UserSerivce
,它将向控制器提供所需的操作。它将在内部注入
ISystemUserCommand
和HttpContext,以便所有控制器都不必执行此任务。您可以使用HttpContext.Current作为静态的,也可以在需要可测试性时将其抽象掉

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


您可以阅读有关过滤器的更多信息。不幸的是,如果您使用过滤器,那么注入过滤器本身并不是那么容易,而且大部分都是通过属性注入或ServiceLocator模式来完成的(这通常并不好)。不过,使用一定量的伏都教可能会做得更好。我认为SimpleInjector有很多关于如何在MVC中将DI应用于过滤器的示例和教程,也许他们现在甚至有一个nuget包来验证这一点。

你有AutoFac的示例吗?我添加了一个AutoFac示例:)这是否仍然允许构造函数注入,还是所有内容都默认为属性注入?我添加了一种方法来定义自动属性注入的范围,并添加了一个指向AutoFac dos的链接。你有AutoFac的示例吗添加了一个autofac示例:)这是否仍然允许构造函数注入,还是所有内容都默认为属性注入?我添加了一种方法来确定自动属性注入的范围,并添加了一个指向autofac dos的链接。我的基本控制器也做了其他事情,我只是没有包括它。我把
OnActionExecuting
放在这里,因为我想用用户信息填充布局页面的viewbags。你认为我应该使用一个过滤器吗?如果你在你的页面上显示一些常见的数据(比如用户信息),我宁愿创建一个特殊的局部视图,在MVC页面中重用。这是一个非常不明显的操作,其他人可能会认为它看起来“神奇”,直到他们理解它是如何工作的。嗯,好的。因此,如果我在页面的导航栏中输入某人的姓名和公司,我会将其移动到部分视图,然后创建一个过滤器来填充部分视图?不,不完全是这样。您可以将导航栏放在部分视图中,并将命令/服务注入负责该视图的控制器中。那你就把你的爸爸