【问题标题】:Creating volatile interfaces instances - dependency injection vs service locator创建易失性接口实例 - 依赖注入与服务定位器
【发布时间】:2017-02-09 02:34:58
【问题描述】:

问题是我有 3 层项目:DataAccess dll 和 Presentation dll 依赖于 Logic dll。在逻辑上,我定义了接口 od IRepository, IMyIdentityUser 等。在 DataAccess 中,我使用 Microsoft Identity 框架向继承 IdentityUser<Guid>IMyIdentityUser 接口的 MyIdentityUser 注册新用户。我也在使用 IoC 容器。 假设我有一个名为“Register”的 Presentation (MVC) 层方法,其参数为“RegisterViewModel viewModel”,它将注册逻辑委托给Logic dll 中的某个类。

  public async Task<ActionResult> Register(RegisterViewModel model)
    {
        if (ModelState.IsValid)
        {
            var user = MyCore.Resolve<IMyIdentityUser>(); //this is service locator 
                                                          // antipattern and I want to get
                                                          // rid of this
            user.UserName = model.Email;
            user.Email = model.Email;


            var userManager = _userManager;


            var result = await userManager.CreateAsync(user, model.Password);
            if (result.Succeeded)
            {
                var signInManager = _signInManager;

                await signInManager.SignInAsync(user, false, false);
                return RedirectToAction("Index", "Home");
            }
            AddErrors(result);
        }


        return View(model);
    }

如您所见,我正在使用服务定位器来获取 MyIdentityUser 的新实例。我不想将其创建为“new MyIdentityUser()”,因为这迫使我与定义了 MyIdentityUser 的 DataAccess dll 使用紧密耦合。 另外,我不想在构造函数参数IMyIdentityUser 中包含并在每次创建 MVC 控制器时强制 IoC 容器创建新的用户实例。 我想我可以使用某种抽象工厂,比如

interface IMyIdentityUserFactory
{
    IMyIdentityUser CreateNewUser(string name, string email); //any other better arguments?
       // not like registerViewModel because 
       // this view model should be defined in presentation logic
}

并将其作为参数传递给控制器​​构造函数(可能在外观参数中带有另一个逻辑连接的参数),但我不确定这一点,因为它通常与传递孤独的IMyIdentityUser 相同。 有更好的方法吗?

【问题讨论】:

    标签: c# asp.net-mvc dependency-injection service-locator


    【解决方案1】:

    另外,我不想在构造函数参数 IMyIdentityUser 和 每次我都强制 IoC 容器创建新的用户实例 创建 MVC 控制器。

    你的前提从一开始就错了。

    1. MVC 控制器没有状态。每个请求都会实例化一个 MVC 控制器(好吧,如果您阅读了此处的第 2 点,您可能会争辩说,如果您实现 IControllerActivator!,您可以更改此默认行为!)
    2. IoC 容器不一定会创建给定注入依赖项的新实例:它取决于组件生命周期。例如,Castle Windsor 将为您提供瞬态、单例、每个请求、每个线程、池化和其他生命周期。瞬态将是唯一肯定会创建给定注入依赖项实例的选择。

    因此,基于您的错误假设,我肯定会在您需要依赖项的任何地方使用构造函数注入。或者属性注入,但是在实现依赖注入时不是首选,因为通常属性注入是可选的

    另一方面,构造注入应该是可行的方法,因为就可测试性而言,每段代码都将独立于其他代码(耦合较少):您可以自动或手动实例化给定的类,也可以自动或手动提供它的依赖关系。

    【讨论】:

    • 公元1. 是的,它们不是有状态的。因此,如果控制器有 4 个方法并且其中只有一个需要来自构造函数的新用户,那么每次我们使用剩余的 3 个方法时让 IoC 容器创建这个用户将是浪费资源 - 假设用户具有瞬态或每个请求的生命周期。但它不能是单例或每个线程,并且池化没有多大意义。最好为注册方法创建此用户only。当然,新用户是非常轻的对象,不会对应用程序性能产生太大影响,但我仍然想知道如何正确地做到这一点。
    • @BartekWójcik 好吧,让我们先在这里讨论一下,然后再为我的答案添加更新......
    • @BartekWójcik 实际上,IControllerActivator 实现可能会实现一些逻辑来确定哪些方法应该激活某些依赖项。使用您的 IoC 框架和一些努力,您应该能够让它发挥作用。
    • 好的,现在我明白了。谢谢
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2011-06-26
    • 2012-08-25
    • 2013-01-21
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多