我想以编程方式设置连接字符串,绝对不会更改任何配置文件/注册表项.
我有这段代码,但不幸的是它引发了一个例外,"配置是只读的".
ConfigurationManager.ConnectionStrings.Clear(); string connectionString = "Server=myserver;Port=8080;Database=my_db;..."; ConnectionStringSettings connectionStringSettings = new ConnectionStringSettings("MyConnectionStringKey", connectionString); ConfigurationManager.ConnectionStrings.Add(connectionStringSettings);
编辑: 问题是我有现有的代码从配置中读取连接字符串.因此,手动或通过资源设置配置字符串似乎不是有效的选项.我真正需要的是一种以编程方式修改配置的方法.
我在博客的帖子中写过这篇文章.诀窍是使用反射来捅取值,以便访问非公共字段(和方法).
例如.
var settings = ConfigurationManager.ConnectionStrings[ 0 ]; var fi = typeof( ConfigurationElement ).GetField( "_bReadOnly", BindingFlags.Instance | BindingFlags.NonPublic ); fi.SetValue(settings, false); settings.ConnectionString = "Data Source=Something";
我正在寻找相同问题的答案,允许用户通过选择本地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)) }
解决这个问题的另一种方法是直接对集合进行操作:
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);
我发现这对我有用:
Configuration config = WebConfigurationManager.OpenWebConfiguration("~"); ConnectionStringsSection section = config.GetSection("connectionStrings") as ConnectionStringsSection; if (section != null) { section.ConnectionStrings["MyConnectionString"].ConnectionString = connectionString; config.Save(); }
这会覆盖现有的连接字符串.
我目前正在使用依赖注入来处理dev/prod与测试环境中的不同连接字符串.如果我想在dev和prod之间移动,我仍然需要手动更改webconfig,但是为了测试我有一个IConnectionStringFactory接口,其默认实现查看Web配置和返回静态值的备用测试配置.这样,当我测试时,我只是将工厂设置为测试实现,它将返回我要求的密钥的测试连接字符串.否则它将在webconfig中查找.
我可以将它扩展到dev vs. prod的另一个实现,但是我在生产程序集中单独实现IConnectionStringFactory以及在我的测试程序集中测试实现时更加舒服.