将强类型配置设置直接访问到 ASP.NET 5 (vNext) 中的 class 库?

Accessing strongly typed configuration settings directly into class library in ASP.NET 5 (vNext)?

我有一个 ASP.NET 5 MVC 6 应用程序。它有一个数据访问库,需要一个连接字符串来连接到数据库。 目前,我正在传递一个强类型的配置设置 class,连接字符串作为 public 属性 从 MVC 控制器(通过 DI 接收)一直传递到数据访问 Class图书馆。

我想知道 class 库是否有更好的方法来使用依赖注入或任何其他机制访问强类型配置设置?

谢谢。

编辑:代码示例

这是从业务层调用的通用 DbTransaction class。

public class DbTransactions<TEntity> where TEntity : DbEntity, new()
{
        private readonly Query _query;

        public DbTransactions(string connectionString)
        {
            _query = new Query(connectionString);
        }

        public TEntity GetById(long id)
        {
            var sqlGenerator = new SqlGenerator<TEntity>();
            var sql = sqlGenerator.GetSelectByIdQuery();
            var mapper = new NMapper.Mapper<TEntity>();
            var cmd = _query.GetNpgsqlCommand(sql, new { id });
            return mapper.GetObject(cmd);
        }
}

查询 class 从提供给它的连接字符串创建连接对象。

您可以让您的服务class依赖于一个接口,例如:

public interface IConnectionFactory {
    string ConnectionString();
}

public class MyDataAccessClass {

    private readonly IConnectionFactory _connectionFactory

    public MyDataAccessClass(IConnectionFactory connectionFactory) {
        _connectionFactory = connectionFactory;
    }

    public void Whatever() {
        var connectionString = _connectionFactory.ConnectionString();
    }

}

然后实现它(尽可能靠近你的组合根):

public class SqlConnectionFactory : IConnectionFactory {
     public string ConnectionString() {
        return "myConnectionString";
     }
}

让接口有你需要的方法或属性。

线像:

public void ConfigureServices(IServiceCollection services)
{
    services.AddSingleton<IConnectionFactory, SqlConnectionFactory>();
}

我同意@Steven 的观点,即使用IOptions<T> 是个坏主意。但是,您可以使用 ConfigurationBinder 扩展将配置的特定部分读出到强类型 POCO class 中。只需确保您在 project.json 的 dependencies 部分的某处有这个:

"dependencies": {
    [other dependencies],
    "Microsoft.Extensions.Configuration.Binder": "1.0.0-rc1-final",
    [other dependencies]
}

只需像往常一样建立您的配置。例如,假设您有一个 Database.json 配置文件,如下所示:

{
  "Database": {
    "ConnectionInfo": {
      "connectionString": "myConnectionString"
    }
  }
}

您可以通过 Startup.cs 中的 Startup 方法构建您的配置:

public IConfiguration Configuration { get; private set; }

public Startup(IHostingEnvironment env, IApplicationEnvironment appEnv) {
  IConfigurationBuilder configBuilder = new ConfigurationBuilder()
    .SetBasePath(appEnv.ApplicationBasePath)
    .AddJsonFile("Database.json")
    .AddEnvironmentVariables()
  Configuration = configBuilder.Build();
}

现在我们可以创建一个 POCO class 来匹配 JSON 配置文件的 "Database:ConnectionInfo" 部分。您可以按照@janhartmann 的建议将其与接口匹配,但这可能是必要的,也可能不是必要的。

public class DatabaseConnectionInfo {
    public string ConnectionString { get; set; }
}

现在,我们怎样才能用 JSON 配置文件中的数据填充 DatabaseConnectionInfo class?一种方法是使用 IOptions<T> 框架类型,但我不喜欢在可以避免的情况下使用框架类型。相反,您可以获得这样的实例:

DatabaseConnectionInfo dbConnInfo = Configuration
  .GetSection("Database:ConnectionInfo")
  .Get<DatabaseConnectionInfo>();

现在您可以将 dbConnInfo 类型注册为类型 DatabaseConnectionInfo 的单例(或者如果您希望拥有不可变的配置设置对象,则注册为接口类型的单例)。在 IoC 容器中注册后,您可以构造函数在需要的地方注入它:

public class DbTransactions<TEntity> where TEntity : DbEntity, new()
{
  private readonly Query _query;

  public DbTransactions(DatabaseConnectionInfo dbConnInfo)
  {
    _query = new Query(dbConnInfo.ConnectionString);
  }

  public TEntity GetById(long id) { ... }
}

我使用了与前面列出的一些方法类似的方法,但我认为它有足够的不同以保证另一个答案。

首先,我定义了一个接口,其中包含我的 class 需要的所有配置。在这种情况下

public interface IDbTransactionsConfiguration {
    string ConnectionString { get; }
}

然后我更改 class 以通过构造函数注入采用此配置

public class DbTransactions<TEntity> where TEntity : DbEntity, new() {
    public DbTransactions(IDbTransactionsConfiguration configuration) {
        ...
    }
}

然后我定义一个 class 来处理我的应用程序的所有配置。

public class MyApplicationConfiguration : IDbTransactionsConfiguration, ISomeOtherConfiguration, etc {
    public string ConnectionString { get; }
    ... other configuration
}

然后我使用某种依赖注入(对我来说通常是 Castle Windsor 或 AutoFac)将这个 class 传递给所有需要它的 classes。

如果由于遗留类型的原因构建DbTransactions太困难,我定义了一个静态版本的 MyApplicationConfiguration 并直接访问它。

有关 this blog post 的更多详细信息。