none
app.configのconnectionStringsを動的に変更した際の更新について RRS feed

  • 質問

  • WinFormのデータベース接続設定でapp.configのconnectionStringsを同DBに格納してある値で動的に変更した後、
    「プロジェクトのクリーン」か「ソリューションのクリーン」を行わないと新しい接続設定に切り替わらないのですが
    切り替える方法もしくはクリーンをコードで行う方法ありましたら教えていただきたいです。
    IDE:Visual Studio Community 2017 C# 
    DB:postgresql-11.1-1-windows-x64

        public partial class Form_dbconfig : Form
        {
            private NpgsqlConnection m_conn = new NpgsqlConnection(MyPrj.Properties.Settings.Default.PostgresConnect);

        // 変数等は省略

            private void button1_Click(object sender, EventArgs e)
            {
                try
                {
                    m_conn.Open();

                    NpgsqlCommand command = new NpgsqlCommand(
                    "SELECT"
                    +" d_id"
                    + ", d_name"
                    + ", d_oct"
                    + ", d_port"
                    + ", d_user"
                    + ", d_pass"
                    + ", d_database_name"
                    + ", d_flg"
                    + " FROM"
                    + " t_dbconfig"
                    + " WHERE d_flg = 'TRUE'"
                    + " ORDER BY d_id;"
                    , m_conn);

                    try
                    {
                        NpgsqlDataReader dr = command.ExecuteReader();
                        while (dr.Read())
                        {
                            for (I = 0; I < dr.FieldCount; I++)
                            {
                                val_d_id = dr[0].ToString();
                                val_d_name = dr[1].ToString();
                                val_d_oct = dr[2].ToString();
                                val_d_port = dr[3].ToString();
                                val_d_user = dr[4].ToString();
                                val_d_pass = dr[5].ToString();
                                val_d_database_name = dr[6].ToString();
                                val_d_flg = dr[7].ToString();
                            }
                        }
                        dr.Close();
                    }
                    finally
                    {
                        m_conn.Close();
                    }

                    //書き込み処理
                    var config = ConfigurationManager.OpenExeConfiguration(ConfigurationUserLevel.None);
                    var connectionStringsSection = (ConnectionStringsSection)config.GetSection("connectionStrings");
                    if (connectionStringsSection != null)
                    {
                        connectionStringsSection.ConnectionStrings[val_d_name].ConnectionString
                            = "Server = " + val_d_oct + "; "
                            + "Port = " + val_d_port + "; "
                            + "User Id = " + val_d_user + "; "
                            + "Password = " + val_d_pass + "; "
                            + "Database = " + val_d_database_name + ";"
                            + "Pooling = False";
                        config.Save();
                        ConfigurationManager.RefreshSection("connectionStrings");
                    }
                }
                catch (Exception ex)
                {
                    MessageBox.Show("保存に失敗しました。\n\n[内容]\n" + ex.Message, Text, MessageBoxButtons.OK, MessageBoxIcon.Error);
                    return;
                }
                finally
                {
                    MessageBox.Show("保存しました。\n\n[内容]\n", Text, MessageBoxButtons.OK, MessageBoxIcon.Information);
                    m_conn.Close();
                    m_conn.Dispose();
                }
            }

    2019年3月22日 4:55

回答

  • 接続文字列を DB から取得して書き換えるとか、そんなことをして破綻しないかが気になりますが、とりあえずそれは置いといて・・・

    Settings から接続文字列を取得し、それを書き換えて Settings に保存し、次回は Settings から書き換えて保存した接続文字列を取得できれば質問者さんの目的は果たせると理解して、先の私のレスをもう少し詳しく説明します。

    これが質問者さんのやりたいことと異なる場合は、どこがどう異なるか連絡ください。

    書き換え対象とする接続文字列は、以下の画像の赤枠の TestConnString のように Settings には普通の string 型としてスコープは「ユーザー」にして登録します。

    そうすると以下の画像のようにプロパティにセッターが設定されます。NORTHWINDConnectionString との違いに注目してください。

    C# のコードからは Properties.Settings.Default.TestConnString で取得できるようになります。

    Form に TextBox と Button をドラッグ&ドロップし、以下のようなコードを書いて変更&保存ができることを確認してみてください。

    using System;
    using System.Collections.Generic;
    using System.ComponentModel;
    using System.Data;
    using System.Drawing;
    using System.Linq;
    using System.Text;
    using System.Threading.Tasks;
    using System.Windows.Forms;
    using System.Security.Principal;
    
    namespace WindowsFormsApplication1
    {
        public partial class Form1 : Form
        {
            public Form1()
            {
                InitializeComponent();
    
                this.textBox1.Text = Properties.Settings.Default.TestConnString;
            }
    
    
            private void button2_Click(object sender, EventArgs e)
            {
                Properties.Settings.Default.TestConnString = this.textBox1.Text;
                Properties.Settings.Default.Save();
            }
            
            private void button3_Click(object sender, EventArgs e)
            {
                this.textBox1.Text = Properties.Settings.Default.TestConnString;
            }
        }
    }


    • 回答としてマーク blue_cars 2019年3月30日 13:03
    2019年3月26日 1:43

すべての返信

  • > private NpgsqlConnection m_conn = 
    >    new NpgsqlConnection(MyPrj.Properties.Settings.Default.PostgresConnect);

    上記を見ると Settings に PostgresConnect という名前で接続文字列が保存されていて、それを、

    MyPrj.Properties.Settings.Default.PostgresConnect = "動的にDB から取得する別の接続文字列";

    というように書き換えて、それを保存したいということですか? であれば、以下のようにして望むことができないでしょうか?

    Properties.Settings.Default.Save();

    これでは質問者さんが期待することが出来なかったら、どこが期待と違うか書いてください。
    2019年3月22日 6:01
  • ご回答ありがとうございます。

    保存自体はされているようなのですが、その保存した接続情報に切り替わらないのです。

    いろいろ試した結果

    「プロジェクトのクリーン」か「ソリューションのクリーン」を行うと新しい接続設定に切り替わるのですが

    そうではない他に切り替える方法もしくはクリーンをコードで行う方法ありましたら教えていただきたいです。

    2019年3月24日 22:23
  • 基本的に exe と同じフォルダーにある exe.config は動的書き換えを想定していません。
    .NET のアプリケーションの構成情報も、マルチユーザーを想定したものとなっており、すべてのユーザーで共有する exe.config を書き換えると困るためです。
    また、現在の config 書き換えはファイルの書き換えだけであり、Settings の中身の更新(再読込)を行っていないと思われます。Reload すれば改善するかもしれません。

    なお、前述したように exe.config を書き換えることは、世の中の潮流(マルチユーザーを想定する、Program Files の中身は変更不可)に逆らっていると思います。
    世の中にリリースするアプリケーションであれば、exe.config を書き換えるのではなく、設定値を「アプリケーション」レベルではなく、「ユーザー」レベルに変えてしまい、Settings.Default の設定値を書き換え、Settings.Default.Save で保存するように変更した方がよいでしょうね。
    (自分一人、特定少数の間だけで使う分にはどちらでも良いと思いますが、ユーザー単位の設定値にした方がわざわざ OpenExeConfiguration しなくて済むので楽だと思います)

    2019年3月24日 23:02
    モデレータ
  • > 保存自体はされているようなのですが、その保存した接続情報に切り替わらないのです。

    どういうコードを書いて、どのような操作をして、どこを見た結果「切り替わらない」と判断されたのでしょうか?
    2019年3月25日 1:14
  • Azulern様、SurferOnWww様

    ご返答ありがとうございます。

    ソリューション エクスプローラーで
    [Properties]の[Settings.settings]をコードで表示にし
    Scope="Application"
          ↓
    Scope="User"に変更

    DB選択フォームのボタンクリック時

    app.configのconnectionStrings変更

    データグリッドビューにDBからapp.configのconnectionStrings接続文字列が入った複数レコードを表示しており

    それを選択することで接続先DBを変更できるようにしたい。

    検証は、ローカル(127.0.1)にあるDBとVM Waer に作ったDB(192.168.0.249)へ接続先を切り替えて行い

    VM Waer側DBを起動していない状態で、接続先をVM Waer側DBに接続を切り替えてみて、

    Program.cs に以下を配置して出力で確認する他

    Console.WriteLine(ConfigurationManager.ConnectionStrings["MyPrj.Properties.Settings.PostgresConnect"]);

    メインフォームを起動してDB接続エラーになるようだと切り替わっているというように検証しています。

    なお、Properties.Settings.Default.Save()で書き直したコードは以下のようなものですが、これだと切り替えも確認できませんでした。(ご指摘いただいたOpenExeConfigurationの方はプロジェクトかソリューションをクリーンすることで切り替わるようです)

    private void button1_Click(object sender, EventArgs e)
    {
    try
    {
    m_conn.Open();

    NpgsqlCommand command = new NpgsqlCommand(
    "SELECT"
    +" d_id"
    + ", d_name"
    + ", d_oct"
    + ", d_port"
    + ", d_user"
    + ", d_pass"
    + ", d_database_name"
    + ", d_flg"
    + " FROM"
    + " t_dbconfig"
    + " WHERE d_flg = 'TRUE'"
    + " ORDER BY d_id;"
    , m_conn);

    try
    {

        NpgsqlDataReader dr = command.ExecuteReader();
        while (dr.Read())
        {
            for (I = 0; I < dr.FieldCount; I++)
            {
                val_d_id = dr[0].ToString();
                val_d_name = dr[1].ToString();
                val_d_oct = dr[2].ToString();
                val_d_port = dr[3].ToString();
                val_d_user = dr[4].ToString();
                val_d_pass = dr[5].ToString();
                val_d_database_name = dr[6].ToString();
                val_d_flg = dr[7].ToString();
            }
        }
        dr.Close();
    }
    finally
    {
        m_conn.Close();
    }

    Properties.Settings.Default["PostgresConnect"] = 
    "Server = " + val_d_oct + "; "
    + "Port = " + val_d_port + "; "
    + "User Id = " + val_d_user + "; "
    + "Password = " + val_d_pass + "; "
    + "Database = " + val_d_database_name + ";";
    Properties.Settings.Default.Save();
    Properties.Settings.Default.Reload();
        }
        catch (Exception ex)
        {
              MessageBox.Show("保存に失敗しました。\n\n[内容]\n"
    + ex.Message, Text, MessageBoxButtons.OK, MessageBoxIcon.Error);
              return;
        }
        finally
        {
              MessageBox.Show("保存しました。\n\n[内容]\n"
    , Text, MessageBoxButtons.OK, MessageBoxIcon.Information);
              m_conn.Close();
              m_conn.Dispose();
        }
    }


    • 編集済み blue_cars 2019年3月25日 14:29
    2019年3月25日 13:12
  • 接続文字列を DB から取得して書き換えるとか、そんなことをして破綻しないかが気になりますが、とりあえずそれは置いといて・・・

    Settings から接続文字列を取得し、それを書き換えて Settings に保存し、次回は Settings から書き換えて保存した接続文字列を取得できれば質問者さんの目的は果たせると理解して、先の私のレスをもう少し詳しく説明します。

    これが質問者さんのやりたいことと異なる場合は、どこがどう異なるか連絡ください。

    書き換え対象とする接続文字列は、以下の画像の赤枠の TestConnString のように Settings には普通の string 型としてスコープは「ユーザー」にして登録します。

    そうすると以下の画像のようにプロパティにセッターが設定されます。NORTHWINDConnectionString との違いに注目してください。

    C# のコードからは Properties.Settings.Default.TestConnString で取得できるようになります。

    Form に TextBox と Button をドラッグ&ドロップし、以下のようなコードを書いて変更&保存ができることを確認してみてください。

    using System;
    using System.Collections.Generic;
    using System.ComponentModel;
    using System.Data;
    using System.Drawing;
    using System.Linq;
    using System.Text;
    using System.Threading.Tasks;
    using System.Windows.Forms;
    using System.Security.Principal;
    
    namespace WindowsFormsApplication1
    {
        public partial class Form1 : Form
        {
            public Form1()
            {
                InitializeComponent();
    
                this.textBox1.Text = Properties.Settings.Default.TestConnString;
            }
    
    
            private void button2_Click(object sender, EventArgs e)
            {
                Properties.Settings.Default.TestConnString = this.textBox1.Text;
                Properties.Settings.Default.Save();
            }
            
            private void button3_Click(object sender, EventArgs e)
            {
                this.textBox1.Text = Properties.Settings.Default.TestConnString;
            }
        }
    }


    • 回答としてマーク blue_cars 2019年3月30日 13:03
    2019年3月26日 1:43
  • SurferOnWww様、返信が遅くなり申し訳ありません

    Settings.settingsにstring型でuserスコープを追加して

    Properties.Settings.Default.PostgresConnect =
                        "Server = " + val_d_oct + "; "
                        + "Port = " + val_d_port + "; "
                        + "User Id = " + val_d_user + "; "
                        + "Password = " + val_d_pass + "; "
                        + "Database = " + val_d_database_name + ";";
    Properties.Settings.Default.Save();

    とすることで望む動作が実現できました。

    (接続文字列)ではなくてstringならできる違いが調べきれなかったのですが

    とりあえず閉じさせていただきたいと思います。

    ご指導いただきありがとうございました。

    2019年3月30日 13:03