ASP.NET:如何从web.config ConnectionString创建连接?

10

如何基于提供程序名称构造一个DbConnection?

示例提供程序名称

  • System.Data.SqlClient
  • System.Data.OleDb
  • System.Data.Odbc
  • FirebirdSql.Data.FirebirdClient

我在IIS服务器的web.config文件中存储了连接字符串:

<connectionStrings>
  <add name="development"
        connectionString="Provider = IBMDA400; Data Source = MY_SYSTEM_NAME; User Id = myUsername; Password = myPassword;" 
        providerName="System.Data.OleDb" />
  <add name="live" 
        connectionString="usd=sa;pwd=password;server=deathstar;" 
        providerName="System.Data.Odbc" />
  <add name="testing" 
        connectionString="usd=sa;pwd=password;server=deathstar;" 
        providerName="System.Data.SqlClient" />
  <add name="offline"
        connectionString="Server=localhost;User=SYSDBA;Password=masterkey;Charser=NONE;Database=c:\data\mydb.fdb"
        providerName="FirebirdSql.Data.FirebirdClient"/>

你可以看到它们都使用不同的提供程序。当我创建连接时,我必须知道要创建哪种 DbConnection,例如:

  • SqlConnection
  • OleDbConnection
  • OdbcConnection
  • FbConnection

connectionStrings 条目包含一个 providerName,但这些不是 DbConnection 子类的名称,而似乎是一个命名空间。

如何基于 providerName 字符串构造一个 DbConnection


public DbConnection GetConnection(String connectionName)
{
    //Get the connectionString infomation
    ConnectionStringSettings cs = 
          ConfigurationManager.ConnectionStrings[connectionName];
    if (cs == null)
       throw new ConfigurationException("Invalid connection name \""+connectionName+"\");

    //Create a connection based on the provider
    DbConnection conn = new DbConnection();

}
3个回答

17
如果您选择这种方法,我认为您需要使用DbProviderFactories类来获取一个DbProviderFactory,以便您可以使用它来构建连接。我没有尝试过这段代码,但我认为它会起作用。可能需要使用DbProviderFactories类上的GetFactoryClasses方法查找提供程序名称并使用InvariantName。
public DbConnection GetConnection(String connectionName)
{
   //Get the connection string info from web.config
   ConnectionStringSettings cs= 
         ConfigurationManager.ConnectionStrings[connectionName];

   //documented to return null if it couldn't be found
   if (cs == null)
      throw new ConfigurationErrorsException("Invalid connection name \""+connectionName+"\"");

   //Get the factory for the given provider (e.g. "System.Data.SqlClient")
   DbProviderFactory factory = 
         DbProviderFactories.GetFactory(cs.ProviderName);

   //Undefined behaviour if GetFactory couldn't find a provider.
   //Defensive test for null factory anyway
   if (factory == null)
      throw new Exception("Could not obtain factory for provider \""+cs.ProviderName+"\"");

   //Have the factory give us the right connection object      
   DbConnection conn = factory.CreateConnection();

   //Undefined behaviour if CreateConnection failed
   //Defensive test for null connection anyway
   if (conn == null)
      throw new Exception("Could not obtain connection from factory");

   //Knowing the connection string, open the connection
   conn.ConnectionString = cs.ConnectionString;
   conn.Open()

   return conn;
}

1
这正是所需之物。秘密的关键在于“提供程序名称”在系统中的某个地方被使用,并且那就是集合DbProviderFactories。每个提供程序都会向DbProviderFactories注册自己;这就是你找到它的方式。 - Ian Boyd

0

请查看this Hanselman博客,了解如何添加自定义构建类型以适配不同的连接字符串名称,这似乎比使用提供程序类型更适合您想要实现的目标。


这不是不同的构建。一个系统必须根据情况连接到各种数据库。 - Ian Boyd
1
啊,我误解了这个例子。我不会想到一个应用程序会同时连接开发、生产和测试环境。 - blu

0
如果特定连接名称(dev、test、prod)的 providerName 从未更改,为什么不能在方法的 connectionName 参数上进行转换,并以此设置 providerName 实例?

因为那不是这个问题。 - Ian Boyd
因为那样只会导致混乱。五年后,一个新的开发人员被分配了将测试数据库从SQL Server迁移到Oracle的任务。他们更新了连接字符串,但结果却是惨败。这种隐藏的假设(即开发数据库使用X数据库提供程序)是引发问题的一种很好的方式。 - Yuliy
老实说,这不是一个好的解决方案。让你的生产代码依赖于动态变化的数据库提供程序,在尝试解决这个问题之前就会让人泪流满面。 - Marc

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接