2008-12-11 114 views
56

我想以编程方式设置连接字符串,绝对不会更改任何配置文件/注册表项。如何在.net中以编程方式设置连接字符串配置?

我有这段代码,但不幸的是它引发一个异常,“配置是只读的”。

ConfigurationManager.ConnectionStrings.Clear(); 
string connectionString = "Server=myserver;Port=8080;Database=my_db;..."; 
ConnectionStringSettings connectionStringSettings = 
    new ConnectionStringSettings("MyConnectionStringKey", connectionString); 
ConfigurationManager.ConnectionStrings.Add(connectionStringSettings); 

编辑: 的问题是,我有现有的代码读取从配置的连接字符串。因此,手动设置配置字符串或通过资源,似乎不是有效的选项。我真正需要的是以编程方式修改配置的方法。

+0

是否要更改配置文件中的连接字符串?用你构建的任何连接字符串动态创建一个新的连接是很容易的......如果这就是你想要做的......但是如果你想写入实际的配置文件,这是一个不同的问题。 – 2008-12-11 16:50:38

回答

105

我已经在post on my blog写了这个。诀窍是使用反射来戳入值,以便访问非公共字段(和方法)。

例如。

var settings = ConfigurationManager.ConnectionStrings[ 0 ]; 

var fi = typeof(ConfigurationElement).GetField("_bReadOnly", BindingFlags.Instance | BindingFlags.NonPublic); 

fi.SetValue(settings, false); 

settings.ConnectionString = "Data Source=Something"; 
+1

如果您使用NHibernate,请参阅http://nhforge.org/wikis/howtonh/dynamically-change-user-info-in-connection-string.aspx – 2009-05-04 06:16:52

+1

谢谢@David。很赞,非常有帮助! – 2011-05-25 21:16:18

+6

伟大的解决方案!如果要添加新的连接字符串,请使用以下命令来添加到ConnectionString集合:`typeof(ConfigurationElementCollection).GetField(“bReadOnly”,BindingFlags.Instance | BindingFlags.NonPublic).SetValue(ConfigurationManager.ConnectionStrings,false) ;` – 2011-10-03 08:56:07

1

您可以改为将其放在资源文件中。它不具有ConfigurationManager类的内置功能,但它可以工作。

假设Resources.resx:

Resources.Default.ConnectionString = "Server=myserver;" // etc

在你的代码

然后:

conn.ConnectionString = Resources.Default.ConnectionString

这是一个黑客,我知道了。

-1

ConfigurationManager用于从配置文件中读取读取

您的解决方案是简单地将conn.ConnectionString设置为您需要的conn字符串。

+3

这实际上并不奏效 - 你会得到一个例外。 – ripper234 2009-03-18 11:03:17

5

我目前使用依赖注入处理dev/prod与测试环境中的不同连接字符串。如果我想要在dev和prod之间移动,我仍然必须手动更改webconfig,但是为了测试,我有一个IConnectionStringFactory接口,它具有一个默认实现,它查看Web配置和一个返回静态值的替代测试配置。这样,当我测试时,我只需将工厂设置为测试实现,它将返回我要求的密钥的测试连接字符串。否则,它会在webconfig中查找。

我可以将其扩展到dev和prod的另一个实现,但我更喜欢在我的生产组合中实现一个IConnectionStringFactory,并且在我的测试组合中实现测试。

0

除了给出的其他答案之外,假设连接字符串不是简单的另一个配置变量或常量,您可以考虑使用SqlConnectionStringBuilder类,而不是直接将字符串连接在一起。

编辑:Ups,对不起刚刚看到你基本上想从另一个来源读取你的连接字符串(完成我猜)。

6

我觉得这对我的作品:

Configuration config = WebConfigurationManager.OpenWebConfiguration("~"); 
ConnectionStringsSection section = config.GetSection("connectionStrings") as   ConnectionStringsSection; 
if (section != null) 
{ 
    section.ConnectionStrings["MyConnectionString"].ConnectionString = connectionString; 
    config.Save(); 
} 

这将覆盖现有的连接字符串。

8

我正在寻找允许用户通过选择本地SQL Server来修改单击应用程序中的连接字符串的相同问题的答案。

下面的代码显示一个用户表单,它联系了所有本地可用的SQL Server并允许他们选择一个。然后它为该服务器构造一个连接字符串并从窗体上的一个变量返回它。代码然后修改配置文件并保存它。

string NewConnection = ""; 
// get the user to supply connection details 
frmSetSQLConnection frm = new frmSetSQLConnection(); 
frm.ShowDialog(); 
if (frm.DialogResult == DialogResult.OK) 
{ 
    // here we set the users connection string for the database 
    // Get the application configuration file. 
    System.Configuration.Configuration config = ConfigurationManager.OpenExeConfiguration(ConfigurationUserLevel.None); 
    // Get the connection strings section. 
    ConnectionStringsSection csSection = config.ConnectionStrings; 
    foreach (ConnectionStringSettings connection3 in csSection.ConnectionStrings) 
    { 
     // Here we check for the preset string - this could be done by item no as well 
     if (connection3.ConnectionString == "Data Source=SQL204\\SQL2008;Initial Catalog=Transition;Integrated Security=True") 
     { 
      // amend the details and save 
      connection3.ConnectionString = frm.Connection; 
      NewConnection = frm.Connection; 
      break; 
     } 
    } 
    config.Save(ConfigurationSaveMode.Modified); 
    // reload the config file so the new values are available 

    ConfigurationManager.RefreshSection(csSection.SectionInformation.Name); 

    return clsDBMaintenance.UpdateDatabase(NewConnection)) 
} 
7

另一种方式来处理,这将是对收集直接操作:

var settings = ConfigurationManager.ConnectionStrings; 
var element = typeof(ConfigurationElement).GetField("_bReadOnly", BindingFlags.Instance | BindingFlags.NonPublic); 
var collection = typeof(ConfigurationElementCollection).GetField("bReadOnly", BindingFlags.Instance | BindingFlags.NonPublic); 

element.SetValue(settings, false); 
collection.SetValue(settings, false); 

settings.Add(new ConnectionStringSettings("ConnectionStringName", connectionString)); 

// Repeat above line as necessary 

collection.SetValue(settings, true); 
element.SetValue(settings, true); 
相关问题