【问题标题】:Accessing strongly typed configuration settings directly into class library in ASP.NET 5 (vNext)?将强类型配置设置直接访问到 ASP.NET 5 (vNext) 中的类库中?
【发布时间】:2016-02-17 12:10:51
【问题描述】:

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

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

谢谢。

编辑:代码示例

这是一个从业务层调用的通用 DbTransaction 类。

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);
        }
}

查询类根据提供给它的连接字符串创建连接对象。

【问题讨论】:

  • 只需在数据访问类中注入IOptions&lt;T&gt;即可。
  • @HenkMollema:将IOptions&lt;T&gt; 注入到您的组件中是a really bad idea
  • 您是否在控制器操作中创建数据访问类?这些类的构造函数长什么样子?
  • @YacoubMassad 否 DataAccess 类不能从控制器操作中访问。控制器和 DataAccess 类之间有一个业务层进行通信。数据访问类没有属性,只有静态方法来执行 CRUD 操作。他们在构造函数上什么都没有。只是默认构造函数。

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


【解决方案1】:

我同意@Steven 的观点,即使用IOptions&lt;T&gt; 是个坏主意。但是,您可以使用 ConfigurationBinder 扩展将配置的特定部分读入强类型 POCO 类。只需确保您在 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 类来匹配 JSON 配置文件的 "Database:ConnectionInfo" 部分。您可以按照@janhartmann 的建议将其与接口匹配,但这可能是必要的,也可能不是。

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

现在,我们如何让DatabaseConnectionInfo 类填充 JSON 配置文件中的数据?一种方法是使用IOptions&lt;T&gt; 框架类型,但是当我可以避免它们时,我不喜欢使用框架类型。相反,您可以获得这样的实例:

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) { ... }
}

【讨论】:

  • 有趣的方法,+1
【解决方案2】:

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

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>();
}

【讨论】:

  • 我正在尝试使用此方法,但我无法理解您所说的“尽可能靠近您的作文根”究竟是什么意思。我确实通过一些帖子试图理解这个术语,我能找到的最好的解释是this。那么我是否应该让 IConnectionFactory 的实现尽可能接近启动类?还是我在这里错过了重点?很抱歉没有充分了解这些概念。
  • 如果您发布您的数据访问代码或您需要使用的类 - 我可以给您一个完整的示例 :-)
  • 我已经编辑了帖子以包含一些代码。如果还不够,请告诉我。
【解决方案3】:

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

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

public interface IDbTransactionsConfiguration {
    string ConnectionString { get; }
}

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

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

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

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

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

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

更多详情请关注this blog post

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2015-07-27
    • 1970-01-01
    • 2016-03-24
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多