如何在.net 中以编程方式设置连接字符串配置?
Posted
技术标签:
【中文标题】如何在.net 中以编程方式设置连接字符串配置?【英文标题】:How do I set a connection string config programmatically in .net? 【发布时间】:2010-09-26 11:28:50 【问题描述】:我想以编程方式设置连接字符串,绝对不更改任何配置文件/注册表项。
我有这段代码,但不幸的是它抛出了“配置是只读的”异常。
ConfigurationManager.ConnectionStrings.Clear();
string connectionString = "Server=myserver;Port=8080;Database=my_db;...";
ConnectionStringSettings connectionStringSettings =
new ConnectionStringSettings("MyConnectionStringKey", connectionString);
ConfigurationManager.ConnectionStrings.Add(connectionStringSettings);
编辑: 问题是我有从配置中读取连接字符串的现有代码。因此,手动或通过资源设置配置字符串似乎不是有效的选项。我真正需要的是一种以编程方式修改配置的方法。
【问题讨论】:
是否要更改配置文件中的连接字符串?使用您构造的任何连接字符串动态创建新连接很容易...如果您想要这样做...但是如果您想写入实际的配置文件,那就是另一个问题了。 【参考方案1】:我已经在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";
【讨论】:
如果您使用 NHibernate,请参阅nhforge.org/wikis/howtonh/… 谢谢@David。很好的回答,很有帮助! 很好的解决方案!如果要添加新的连接字符串,请使用以下命令启用添加到 ConnectionString 集合:typeof(ConfigurationElementCollection).GetField("bReadOnly", BindingFlags.Instance | BindingFlags.NonPublic).SetValue(ConfigurationManager.ConnectionStrings, false);
使用反射将属性更改为可写似乎有些错误,但是该死,它有效!
这些东西是必要的,这就是我讨厌 .NET 的原因。 @Simon_Weaver 在它不起作用的意义上没有错;喜欢... 道德上错了。【参考方案2】:
解决此问题的另一种方法是直接对集合进行操作:
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);
【讨论】:
这很好用,但类似于 Andrew McClellan 上面的答案,对于 .Net 5(可能还有所有 2.1+),两者都需要在 GetField 中为 _readOnly。【参考方案3】:我正在寻找关于允许用户通过选择本地 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))
【讨论】:
仅供参考,这会导致您的应用程序域重新加载,因此请谨慎使用【参考方案4】:我发现这对我有用:
Configuration config = WebConfigurationManager.OpenWebConfiguration("~");
ConnectionStringsSection section = config.GetSection("connectionStrings") as ConnectionStringsSection;
if (section != null)
section.ConnectionStrings["MyConnectionString"].ConnectionString = connectionString;
config.Save();
这会覆盖现有的连接字符串。
【讨论】:
小心更改 web.config 文件,因为它会导致工作进程重新启动。我试图在 ApplicationStart 事件中将 Connectionstring 设置为基于文件的数据库,这导致每个访问的页面都重新启动应用程序... 确实如此。我将其用作管理工具功能来加密和解密共享主机帐户上的 web.config。正如 Thomas 所指出的,您不希望将其作为会话或应用程序启动的一部分。 +1:这非常适合我的目的(集成测试)。但是,因为我的生产代码使用ConfigurationManager
,所以一旦我更新了测试中的部分,我就必须使用ConfigurationManager.RefreshSection("connectionStrings");
。
@AlexHumphrey 如果您使用 Remove() 和 Add() 而不是索引和分配,则不必这样做。我还没有验证这一点,但我所知道的是我使用 Clear() 和 Add() 并且它对我来说很好。
这可能在 ASP.NET 下工作(我不太确定),但它绝对不在任何不自动重新加载的可执行文件中工作(例如,控制台应用程序)。在运行之前已经加载了配置,这意味着连接字符串永远不会改变。【参考方案5】:
我目前正在使用依赖注入来处理 dev/prod 与测试环境中的不同连接字符串。如果我想在 dev 和 prod 之间移动,我仍然必须手动更改 webconfig,但是为了测试,我有一个 IConnectionStringFactory 接口,它有一个查看 web 配置的默认实现和一个返回静态值的替代测试配置。这样,当我测试时,我只需将工厂设置为测试实现,它将返回测试连接字符串以获取我要求的密钥。否则它将在 webconfig 中查找。
我可以将它扩展到 dev 与 prod 的另一个实现,但我更愿意在我的生产程序集中使用 IConnectionStringFactory 的单个实现,在我的测试程序集中使用测试实现。
【讨论】:
【参考方案6】:您可以将其放在资源文件中。它没有 ConfigurationManager 类的内置功能,但可以工作。
假设 Resources.resx:
Resources.Default.ConnectionString = "Server=myserver;" // etc
然后在你的代码中:
conn.ConnectionString = Resources.Default.ConnectionString
我知道这是一个黑客攻击。
【讨论】:
【参考方案7】:从 .net Core 2.1 起,名称似乎已更改 修改大卫加德纳的答案 这种方式应该适用于引用新旧版本:
var 设置 = ConfigurationManager.ConnectionStrings[0];
var fi = typeof( ConfigurationElement ).GetField( "_bReadOnly", BindingFlags.Instance | BindingFlags.NonPublic );
if(fi == null)
fi = typeof(System.Configuration.ConfigurationElementCollection).GetField("_readOnly", BindingFlags.Instance | BindingFlags.NonPublic);
fi.SetValue(settings, false);
settings.ConnectionString = "Data Source=Something";
【讨论】:
【参考方案8】:除了给出的其他答案,并且假设连接字符串不仅仅是另一个配置变量或整体常量,您可以考虑使用SqlConnectionStringBuilder 类而不是直接将字符串连接在一起。
编辑:Ups,抱歉刚刚看到您基本上想从另一个来源读取连接字符串(我猜是完整的)。
【讨论】:
【参考方案9】:ConfigurationManager 用于读取配置文件。
您的解决方案是简单地将 conn.ConnectionString 设置为您需要的 conn 字符串。
【讨论】:
以上是关于如何在.net 中以编程方式设置连接字符串配置?的主要内容,如果未能解决你的问题,请参考以下文章