【问题标题】:ASP.NET Core DI in a class library?类库中的 ASP.NET Core DI?
【发布时间】:2019-02-19 21:12:20
【问题描述】:

我有一个引用典型 .NET Core 类库的“数据访问层”项目的 ASP.NET Core 2.1 项目。

数据访问层需要来自 ASP.NET Core 项目中 appsettings.json 的连接字符串。

我创建了一个像这样的简单容器:

public class DatabaseConnectionString : IDatabaseConnectionString
{
    private readonly string _connectionString;

    public DatabaseConnectionString(string connectionString)
    {
        _connectionString = connectionString;
    }

    public string ConnectionString {
        get { return _connectionString; }
        set {  }
    }
}

在 ASP.NET Core Startup.cs > ConfigureService 我有这个:

services.AddScoped<IDatabaseConnectionString>(p => new DatabaseConnectionString(Configuration.GetConnectionString("DefaultConnection")));

我知道我可以将 IDatabaseConnectionString 添加到 ASP.NET 中控制器的构造函数中以获取容器。但是在类库中如何获得它?我不想从控制器一路向下传递,只是将 IDatabaseConnectionString 添加到类库中类的构造函数中是行不通的。

我可能需要一个服务,我可以要求创建一个类的对象并让服务用正确的对象填充构造函数接口?

例如在这个类中填写IDatabasConnectionString:

public class UserFactory : FactoryBase
{
    private readonly IDatabaseConnectionString _iDatabaseConnectionString;

    public UserFactory(IDatabaseConnectionString connectionString)
    {
        _iDatabaseConnectionString = connectionString;
    }

}

【问题讨论】:

  • 希望DatabaseConnectionString 的空设置器只是一个错字或什么的。请不要创建一个空的二传手。如果不应该设置,则删除设置器。
  • “类库中类的构造函数的IDatabaseConnectionString不起作用”为什么不呢?
  • I dont want to pass it all the way down from the controller 是什么意思?你把它通过了什么?
  • 谢谢,setter 已修复 :)
  • @Banshee 但是为什么需要将它放入控制器并将其传递给 5-10 个方法?你为什么不让你的 DAL 依赖于 IDatabaseConnectionString 本身,让 IoC 容器解决它?

标签: c# asp.net-core dependency-injection


【解决方案1】:

我知道我可以将 IDatabaseConnectionString 添加到 ASP.NET 中控制器的构造函数中以获取容器。

不,这不是必需的,而且是错误的。

仅仅将IDatabaseConnectionString添加到类库中类的构造函数是行不通的。

它不起作用,因为您需要创建将使用连接字符串的服务将其添加到服务容器中。

例如:

public class Repository: IRepository
{
    public Repository(IDatabaseConnectionString databaseConnectionString)
    {
        _databaseConnectionString = databaseConnectionString;
    }
}

public class ServiceThatRequiresDatabase : IServiceThatRequiresDatabase
{
    public ServiceThatRequiresDatabase(IRepository repository)
    {
        _repository = repository;
    }
}

// ...
services.AddScoped<IRepository, Repository>();
services.AddScoped<IServiceThatRequiresDatabase, ServiceThatRequiresDatabase>();


public class HomeController : Controller
{
    public HomeController(IServiceThatRequiresDatabase service)
    {
        _service = service;
    }
}

顺便说一句,正如@YeldarKurmangaliyev 所说,如果你想将它设为只读,你的 DatabaseConnectionString 应该是这样的:

public class DatabaseConnectionString : IDatabaseConnectionString
{
    public string ConnectionString { get; }

    public DatabaseConnectionString(string connectionString)
    {
        ConnectionString = connectionString;
    }
}

【讨论】:

  • 如果 HomeController 不是控制器,只是一个普通类,我将如何创建它并让注入系统注入 ServiceThatRequiresDatabase?
  • @Banshee 好吧,有些代码会使用该类,不是吗?该代码通常是一个控制器,因为这是进入应用程序的正常方式。你在处理什么场景?
  • @Banshee 阅读这篇文章,对你的问题有很好的解释:freecontent.manning.com/…
  • 控制器可能是调用的起点,但它位于需要连接字符串的 DAL 中。我不想通过说 5-10 种不真正使用连接字符串的方法来传递连接字符串。我希望能够在 DAL 中创建一个类,该类将使用 DI 根据服务寄存器填充构造函数中的接口(在这种情况下可能是单例)。这是错误的做法吗?
  • @Banshee 只有真正需要 IDatabaseConnectionString 的类才应该请求它。这是依赖注入之美的一部分。您的控制器不需要帮助 DAL 获取连接字符串。它应该做的只是依赖于 DAL(通过接口,而不是具体类型)。创建 DAL 并满足其依赖关系是 IoC 容器的工作,而不是控制器的工作。我强烈建议您观看this entire video,以便您真正了解其工作原理。
【解决方案2】:

控制器和类库中的类没有区别。你需要

  1. 在类库中定义一个类并将IDatabaseConnectionString注入其中。您的UserFactory 是正确的方式。

  2. 为 DI 注册 UserFactory

    serviceCollection.AddScoped<IUserFactory, UserFactory>();
    
  3. 由 DI 解析 UserFactory。例如,在某些控制器中使用 UserFactory 作为构造函数参数。一切都由 DI 自动连接。

    public MyController(IUserFactory userFactory)
    {
        _userFactory = myUserFactory;
    }
    

Here 是理解作文根的好解释。

【讨论】:

  • 如何在您的示例中实例化 MyController 类?
  • MyController 必须由 DI 创建。所以它必须为 DI 注册并解决它。原理是一样的。如果MyController是Asp.Net控制器类,则自动注册。
  • 谢谢,我会看看你的链接。
猜你喜欢
  • 2019-02-15
  • 2020-06-09
  • 2017-07-28
  • 2020-07-20
  • 1970-01-01
  • 2016-05-26
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多