.net で接続文字列構成をプログラム的に設定するにはどうすればよいですか?
-
21-08-2019 - |
質問
構成ファイルやレジストリ キーをまったく変更せずに、プログラムで接続文字列を設定したいと考えています。
このコードがありますが、残念ながら「構成は読み取り専用です」という例外がスローされます。
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 を選択してクリック 1 回のアプリケーションで接続文字列を変更できるようにすることについて、同じ質問に対する答えを探していました。
以下のコードは、ローカルで利用可能なすべての 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 と prod で異なる接続文字列を処理しています。テスト環境。dev と prod の間で移動したい場合は、引き続き webconfig を手動で変更する必要がありますが、テスト用に、web config を参照するデフォルトの実装と、静的な値を返す代替テスト構成を備えた IConnectionStringFactory インターフェイスを用意しています。そうすれば、テスト時にファクトリをテスト実装に設定するだけで、要求したキーのテスト接続文字列が返されます。それ以外の場合は、Webconfig を参照します。
これを開発対開発の別の実装に拡張できます。prod ですが、運用アセンブリに IConnectionStringFactory の単一実装を配置し、テスト アセンブリにテスト実装を配置する方が快適です。
代わりにリソース ファイルに置くこともできます。ConfigurationManager クラスの組み込み機能はありませんが、機能します。
Resources.resx を想定すると、次のようになります。
Resources.Default.ConnectionString = "Server=myserver;" // etc
次に、コード内で次のようにします。
conn.ConnectionString = Resources.Default.ConnectionString
それはハッキングです、私は知っています。
与えられた他の回答に加えて、接続文字列が全体として単なる別の構成変数または定数ではないと仮定すると、次の使用を検討できます。 SqlConnectionStringBuilder 文字列を直接連結するのではなく、クラスを使用します。
編集:すみません、あなたは基本的に別のソースから接続文字列 (完全だと思います) を読み取りたいと考えていることがわかりました。
.NET Core 2.1のように命名が変更されたように見えます。この方法でDavid Gardinerの答えを修正すると、新しいバージョンと古いバージョンを参照するために機能するはずです。
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";
ConfigurationManager は次の目的で使用されます。 読む 設定ファイルから。
解決策は、単に conn.ConnectionString を必要な conn 文字列に設定することです。