控制器动作的构造函数参数

时间:2016-03-21 21:30:53

标签: asp.net-mvc-5

我正在尝试创建一个自定义管理器,它在调用时在控制器中传递,我在理解c#中新MVC5项目的当前实现时遇到了麻烦。

这是默认实现:

public AccountController(ApplicationUserManager userManager, ApplicationSignInManager signInManager )
{
    UserManager = userManager;
    SignInManager = signInManager;
}

首先是它们的声明:

public ApplicationSignInManager SignInManager
{
    get
    {
        return _signInManager ?? HttpContext.GetOwinContext().Get<ApplicationSignInManager>();
    }
    private set 
    { 
        _signInManager = value; 
    }
}

public ApplicationUserManager UserManager
{
    get
    {
        return _userManager ?? HttpContext.GetOwinContext().GetUserManager<ApplicationUserManager>();
    }
    private set
    {
        _userManager = value;
    }
}

根据我的理解,当Startup.Auth.cs中第一次创建应用程序时,会创建SignInManager和UserManager,如下所示:

app.CreatePerOwinContext<ApplicationUserManager>(ApplicationUserManager.Create);
app.CreatePerOwinContext<ApplicationSignInManager>(ApplicationSignInManager.Create);

所以现在每当我调用UserManager时,我都会得到第一次项目运行时创建的第一个实例。

我有2个问题。问题1是我上面说的任何错误,我对MVC5如何工作有错误的理解吗?

问题2:如何在控制器中生成并传递UserManager和SignInManager?创建管理器的第一个实例并将其传递给控制器​​的代码在哪里?我假设它是app.CreatePerOwnContext that does it。如果是这样,那么我可以创建自己的经理,然后以相同的方式将其注册到Owin并在整个项目中重复使用吗?如果我这样做而不缓存它,我的代码是否会从数据库中获取最新数据?

1 个答案:

答案 0 :(得分:4)

你所展示的代码来自IMO非常丑陋的MVC5模板,该模板开箱即用,但做了一些丑陋的事情。

这个构造函数:

public AccountController(ApplicationUserManager userManager, 
       ApplicationSignInManager signInManager)

让你觉得OWIN会自动为你注入经理人。但实际情况并非如此。这就是为什么模板带有您在问题中提供的丑陋属性。如果不对模板进行任何更改,则会调用默认构造函数(也存在于模板中)。要尝试它,只需删除或评论默认构造函数,您就会看到AccountController无法再创建。

所以实际发生的情况是,两个管理人员都使用所提供属性的getter中的Service Locator anti pattern

  

所以现在每当我调用UserManager时,我都会得到第一次项目运行时创建的第一个实例?

不是不是这样。这一行:

 app.CreatePerOwinContext<ApplicationUserManager>(ApplicationUserManager.Create);

确实是为两位经理的Create方法创建委托。经理被缓存在Owin请求中。下一个请求再次调用代理,您将得到一个新的ApplicationUserManager等。

为了更加冗长,这一行可以改写为:

Func<ApplicationUserManager> userManagerFactory = () => ApplicationUserMangager.Create();
app.CreatePerOwinContext<ApplicationUserManager>(userManagerFactory);

所以如果你在这里断点:

public ApplicationUserManager UserManager
{
    get
    {
        // place breakpoint here
         return _userManager ?? HttpContext.GetOwinContext().GetUserManager<ApplicationUserManager>();
    }
// ....

您会看到在单步执行代码时,您将点击创建UserManagerFactory的行,而Create()将调用ApplicationUserManager的{​​{1}}方法。

  

如何在控制器中生成并传递UserManager和SignInManager

不是!你需要使用依赖注入。

  

如果是这样,我可以创建自己的经理,然后以相同的方式将其注册到Owin并在整个项目中重复使用

是的,你可以。您可以完全重构您自己获得的ApplicationUserManager&#39;在模板中。只要您为&#39; CreatePerOwinContext&#39;提供工厂方法。扩展方法。

  

如果我这样做而不缓存,我的代码是否会从数据库中获取最新数据?   实例基于每个请求库进行缓存。所以每个请求你都会得到一个新的DbContext等。

我不确定你对dependency injection的熟悉程度,但MVC5是一个非常简单的框架,从它开始,IMO。

我曾写过blogpost如何配置我选择的DI容器(Simple Injector)以与MVC5模板一起使用。 我还在这里就这个模板写了几个答案:特别是这个one,你应该感兴趣。这个one也很有趣!