使用带有运行时参数的构造函数通过 Unity 进行依赖关系注入

本文关键字:Unity 依赖 注入 关系 构造函数 运行时 参数 | 更新日期: 2023-09-27 18:33:52

我已经掌握了依赖注入的基础知识,但我正在努力尝试使用 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();
}

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

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

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

使用带有运行时参数的构造函数通过 Unity 进行依赖关系注入

搜索参数不应该是构造函数的一部分;它应该是"搜索"方法的一部分。 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);
}

公司用户搜索服务:

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
}

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

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

更新

我同意必须从控制器中删除依赖项。正如您@Topojijo建议在这种情况下可以使用UserSearchService工厂。猜测您有几个子宫颈,您需要为每个子宫颈建立一个工厂,如果它们的数量很大,可能会有开销。在这种情况下,最好直接从 Unity 容器解析服务并将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);
}