【问题标题】:Dependency Injection With Unity Using Constructors With Runtime Parameters使用带有运行时参数的构造函数的 Unity 依赖注入
【发布时间】:2015-02-07 13:55:00
【问题描述】:

我已经掌握了依赖注入的基础知识,但我正在努力尝试在使用 Unity 的 MVC API C# 应用程序中将其正确组合在一起。我遇到的问题是我将拥有一个具有方法的控制器,并且在该方法中它会说两个对象。其中一个对象将依赖于数据访问层,而另一个则没有。我不太确定如何设置。

假设我有一个控制器,它使用以下方法从搜索对象中获取用户。它还使用 SearchParameters 对象来执行搜索。如果您不使用名称进行搜索,您将获得所有结果,或者如果您输入名称,您将获得任何具有该名称的用户。

public Users[] GetUsers(string name) {
    Company.SearchParameters searchParams = new Company.SearchParameters(name);
    Company.UserSearchService searchService = new Company.UserSearchService(searchParams);

    return searchService.Search();
}

这当然是一个超级简化的版本,但在这种情况下,Search 方法中的 UserSearchService 正在执行显式数据库调用。所以我知道这是我必须给予它的依赖。 SearchParameters 实际上只是一个保存数据的类。

这是我不确定下一步该做什么的地方。控制器本身没有依赖关系,但由于 UserSearchService 没有,我不确定如何使用统一我正确设置它并考虑构造函数的运行时值。我也不确定 SearchParameters 是否应该被视为依赖项。

此外,如果重要的话,SearchParameters 和 UserSearchService 没有任何类型的支持接口,并且此控制器上还有其他方法可以与其他类交互,这些类对数据访问层依赖项有类似需求,例如可能是 Company.UserAccount。

【问题讨论】:

  • 根据您的代码,Company.UserSearchService 除了Company.SearchParameters 之外没有依赖项(或者您省略了什么?)但是您说 Controller 本身没有依赖项,但由于 UserSearchService 有
  • 在 UserSearchService 的 Search 方法中,它有一个对 Database.Execute 的显式调用,这是一个命中数据库的静态方法,因此这是当前依赖项所在的位置。我想解决这个问题,所以它实际上是可测试的。

标签: c# asp.net-mvc dependency-injection dependencies unity-container


【解决方案1】:

我在这里看到两个任务。第一个是重构,其中静态依赖项必须替换为接口。第二个任务是在 IoC 容器中注册你的东西。

对于第一个任务,您需要的最低限度是将UserSearchService 中对Database 的所有引用替换为IDatabase 接口(这样它也可以被模拟)并允许它传递给构造函数(构造函数注入)。为了能够为服务提供IDatabase 的实例,您必须为控制器创建相同的依赖项(再次构造函数注入)。然后注册IDatabase实现如this post所示。

更新

我同意必须从控制器中删除依赖项。正如您@Topojijo 建议的那样,可以在这种情况下使用UserSearchService 的工厂。假设您有几个 cervices,您需要为每个 cervices 制造一个工厂,如果它们的数量很大,可能会有开销。在这种情况下,最好从 Unity 容器中 resolve the service directly 并将 searchParams 移动到 Search 方法:

public Users[] GetUsers(string name) {
    Company.SearchParameters searchParams = new Company.SearchParameters(name);
    Company.UserSearchService searchService = container.Resolve<Company.UserSearchService>();

    return searchService.Search(searchParams);
}

【讨论】:

  • 这就是我起初的想法,但后来我读到将依赖项传递给控制器​​是错误的,因为控制器本身从不使用该依赖项。我所看到的是,控制器基本上通过了一个构建 UserSearchService 的工厂,并且在该工厂中使用了 Unity。
  • 是的,没错,这是更高级的解决方案。我已经更新了我的答案。
【解决方案2】:

搜索参数不应该是构造函数的一部分;它应该是“搜索”方法的一部分。 SearchParameter 对象甚至不应该在 UserSearchService 类(封装)之外为人所知。正如 neleus 建议的那样,应该进行一些重构。至少,为了让事情顺利进行,它应该被重构为类似这样的东西:

public Users[] GetUsers(string name) {
    // Or however you end up with your UserSearchService object.  
    // Ideally as an interface and an injected dependency...
    Company.UserSearchService searchService = new Company.UserSearchService();

    return searchService.Search(name);
}

Company.UserSearchService:

public Users[] Search(string name) {
    // A factory would be a better option.  This should also be an interface.
    Company.SearchParameters searchParams = new Company.SearchParameters(name);

    // Your logic here
}

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2021-02-04
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多