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

时间:2015-11-16 11:47:23

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

我有一个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);
        }
}

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

3 个答案:

答案 0 :(得分:4)

我同意@Steven使用IOptions<T>是一个坏主意。但是,您可以使用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; }
}

现在,我们如何才能使用JSON配置文件中的数据填充DatabaseConnectionInfo类?一种方法是使用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) { ... }
}

答案 1 :(得分:0)

您可以让服务类依赖于某个接口,例如:

from:   Smith, Paul
to:     Paul Smith


INSTR(emp.NAME, ',') +1, LENGTH(emp.NAME)-1)|| ' '||SUBSTR(emp.NAME, 1, INSTR(emp.NAME, ',')-1)

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

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

答案 2 :(得分:0)

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

首先,我定义了一个具有我的类所需的所有配置的接口。在这种情况下

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
}

然后我使用某种Depenendency Injection(通常使用Castle Windsor或AutoFac)将此类传递到所有需要它的类中。

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

有关this blog post的更多详情。