none
DB接続文字列をクライアントからWebServiceに渡す方法について RRS feed

  • 質問

  • はじめまして

    C#のWindowsアプリ フレームワークは4.0
    DBの参照や登録はWebServiceを使用し業務アプリを開発しています。

    現在はDBの接続文字列をweb.configに持っているのですが、
    リーダーの考えでINIファイルに持たせることになりました。

    現在のWebServiceのソースの一例です。(接続文字列はWeb.configに持っている)
    public class SysDate : System.Web.Services.WebService
    {
        SqlConnection con;
        private SqlDataAdapter dadp;

        public SysDate () {}
        [WebMethod]
        public DataSet GetSysDate()
        {
            DataSet ds = new DataSet();
            string DBConnString = ConfigurationManager.AppSettings["DBConnString"];
            try
            {
                con = new SqlConnection(DBConnString);
                //サーバー日付を取得
                dadp = new SqlDataAdapter("SELECT getdate()", con);
                dadp.Fill(ds);
            }
            catch (Exception){}
            finally
            {
                dadp.Dispose();
                con.Close();
                con.Dispose();
            }
            return ds;
        }
        [WebMethod]
        public stirng GetSysDateStirng()
        {
            DataSet ds = new DataSet();
            string DBConnString = ConfigurationManager.AppSettings["DBConnString"];
            try
            {
                con = new SqlConnection(DBConnString);
                //サーバー日付を取得
                dadp = new SqlDataAdapter("SELECT getdate()", con);
                dadp.Fill(ds);
            }
            catch (Exception){}
            finally
            {
                dadp.Dispose();
                con.Close();
                con.Dispose();
            }
            return ds.Tables[0].Rows[0][0].ToString();
        }
    }
    クライアント側では上記のWebServiceを
    //日付の取得
    SysDate sd = new SysDate();
    Label1.Text = sd.GetSysDate();
    Label2.Text = sd.GetSysDateStirng();
    このようにして使用しています。

    INIファイルにDB接続情報を持たせた場合、
    GetSysDate()とGetSysDateStirng()の引数に
    DB接続情報を追加すればいいのはわかるのですが、
    既に多くの画面を開発していて、
    修正にかなりの時間がかかります。

    修正個所を最小限にする方法があれば、
    ご教授ください。お願いします。

    2011年8月5日 2:59

回答

  • 接続文字列をクライアントのINIに書く=クライアントはDBのアドレスを知っている

    なのだから、クライアントはサーバーに接続しなくても、直接DBに接続すればいいのに…

    • 回答の候補に設定 山本春海 2011年8月16日 7:05
    • 回答としてマーク 山本春海 2011年8月23日 6:26
    2011年8月6日 3:45
  • クライアント側に DB 接続文字列を持たせるということは、「Web サービスの実装内容をクライアントが意識しなくてよい」「Web サービスが DB を使用していることすらクライアントが意識しなくてよい」「DB 接続の設定を局所化する」などといった、アプリケーションのレイヤー構造のメリットを壊してしまいますし、他の方々も指摘されている通り、DB 接続文字列がネットワーク上をバンバン流れるのはセキュリティ的にどうかとも思いますが、ちょっと違った反応をしてみます。(きっと何らかの事情で、そういう実装をせざるを得ないのだろう、と好意的に解釈してみます。)

    # 本当は、なぜ各クライアントに DB 接続文字列を持たせようとするに至ったのか、リーダーの考えを知りたいところですが。
    # もしリーダーが間違った道に進もうとしているのであれば、それを羽交い絞めにしてでも思いとどまらせるのがメンバーの務めだとは思う。

    WebService側のpublic SysDate ()
    で引数の接続文字列をPrivateの変数に格納して
    ここの処理で使用できればと思っていたのです。


    Web サービスはステートレスでなければいけないので、private 変数に状態を保持してはダメです。
    SysDate sd = new SysDate();
    Label1.Text = sd.GetSysDate();
    Label2.Text = sd.GetSysDateStirng();


    同じインスタンスを使用しているように見えるかもしれませんが、Web サービスは別のインスタンスになります。次の記事が分かりやすいです。

    Webサービスのメソッド間でデータを共有する方法―日経ソフトウエア 2002年12月号特集2関連記事
    http://www15.nikkeibp.co.jp/software/special/200212toku2/0212tk2a.html

    Web サービスの間で状態を保持するには、最初に かずき_okazuki さんが回答されているような Session を使う方法しかないと思います。

    方法 : ASP.NET を使用して作成した Web サービスで状態を管理する
    http://msdn.microsoft.com/ja-jp/library/hk34sw2t.aspx

    なのですが、今回のケースですと

    ・ConfigurationManager 経由で DB 接続文字列を取得している部分を全部書き換えないといけない
    ・Session 変数には状態が変化するような揮発性の情報を入れるのが一般的
    ・Session が切れることの考慮も一応しておきたい

    と思いますので、DB 接続文字列のような固定の情報は、各 Web サービス メソッドの引数として渡してしまうのがスッキリすると思います。
    (佐祐理 さんの回答のように、そもそも Web サービスを使わないという意見が一番スッキリするのかも。)

    # クライアントが DB 接続文字列を引き渡すことに反対派であることに変わりはないです。
    • 回答の候補に設定 山本春海 2011年8月16日 7:05
    • 回答としてマーク 山本春海 2011年8月23日 6:26
    2011年8月7日 2:34
  • 1画面1WebServiceはいいとして、それでなぜweb.configが画面数ぶんあるのかわかりません・・・。もしかして、1画面1Webアプリケーション(そしてこのWebアプリの中に1サービスがある)なのでしょうか。

    普通は1つのWebアプリケーション内にWebサービスを複数配置して、web.configに接続文字列を格納しておくのが一般的だと思います。

    もし、1画面1Webアプリケーションだとした場合ですがweb.configは1つにしておいて各Webアプリケーションにリンクとしてweb.configを追加したりできないでしょうか。そうすれば、1つのweb.configをメンテするだけで大丈夫だと思います。


    かずき Blog:http://d.hatena.ne.jp/okazuki/ VS 2010のデザイナでBlendのBehaviorをサポートするツール公開してます。 http://vsbehaviorsupport.codeplex.com/
    • 回答の候補に設定 山本春海 2011年8月16日 7:05
    • 回答としてマーク 山本春海 2011年8月23日 6:26
    2011年8月8日 1:13
  • 画面が100本くらいあるシステムのため、
    100本のWebServiceがあるのです。ということは
    100本のWeb.configがあり、そこに接続文字列が
    あります。


    一斉につっこまれそうな話ですが、あえて触れずにおくとして。

    各 Web サービスの Web.config では接続文字列を書かないでおいて、Web サイトレベル (wwwroot の Web.config) に接続文字列を書けばいいように思います。試してはないですが。
    Machine.config に書いてしまうのは、ちとやりすぎかな。

    [INFO] ASP.NET の構成の概要
    http://support.microsoft.com/kb/307626/ja

    Web.config が 100 個なんて、尋常な話とは思えないですけれども。
    • 回答の候補に設定 山本春海 2011年8月16日 7:05
    • 回答としてマーク 山本春海 2011年8月23日 6:28
    2011年8月8日 1:32
  • 画面が100本くらいあるシステムのため、
    100本のWebServiceがあるのです。ということは
    100本のWeb.configがあり、そこに接続文字列が
    あります。本番環境にリリースする時に100個所の
    接続文字列を修正するのは時間がかかり、また、
    修正漏れが発生するため、クライアントのiniファイルに
    持たす話になりました。

    これ、クライアントが 200 台あったら、200か所のINIファイルを修正しないといけないですよね…。

    単純に、階層上で親になる web.config 1つに書けば、子階層にある 100 個の web.config には書かないでもよいと思います。最悪でも、サーバ側に INI ファイル1つを置いて、サーバ側で web.config のかわりに、その INI ファイルを見ればよいんじゃないかと思いますが…。(web.config と違って、INI ファイルは書き換えてもサービスを再起動してくれないので、そのあたりの仕組み作りが大変だとは思いますけど)

     

    • 回答の候補に設定 山本春海 2011年8月16日 7:05
    • 回答としてマーク 山本春海 2011年8月23日 6:27
    2011年8月8日 3:31
  • 先に紹介したページ、

    接続文字列と構成ファイル (ADO.NET)
    http://msdn.microsoft.com/ja-jp/library/ms254494.aspx

    の「外部構成ファイルの使用」のセクションに書いてあるように
    する手もあります。本番環境に移す時には、web.config を書き換
    えるのではなく、外部構成ファイルを差し替えるというのはいかが
    ですか?

     

    • 回答の候補に設定 山本春海 2011年8月16日 7:04
    • 回答としてマーク 山本春海 2011年8月23日 6:27
    2011年8月8日 13:06

すべての返信

  • usingブロックを使って無かったり、クライアントのINIファイルにDB接続情報を持たせる等から若干不安を覚えます。そして、毎回ネットワーク上をDBの接続文字列が流れるのですがいいのでしょうか・・・。凄く不安です。

    本題の修正箇所を最小限にする方法ですが、修正箇所を最小限にするという目的のために手段を択ばないとすると、どこかで一度クライアントからサーバにDBの接続文字列を渡して置いて、それをSessionに格納します。あとはWebサービスで、Session内から接続文字列を参照するようにするというのはどうでしょうか。

    参考:http://d.hatena.ne.jp/Tsuto/20070828/1188289245

    激しくおすすめしませんが・・・。おとなしくweb.configに持たせましょう・・・。


    かずき Blog:http://d.hatena.ne.jp/okazuki/ VS 2010のデザイナでBlendのBehaviorをサポートするツール公開してます。 http://vsbehaviorsupport.codeplex.com/
    2011年8月5日 4:42
  • リーダー様の考えは、INI ファイルを各クライアントに持たせて、各クライアントから DB 接続文字列を指定しろ、ということなのでしょうか?
    それとも単に、Web.config でなく DB 接続文字列だけ INI ファイルに分離して、サーバーのどこかに置いておけ、ということなのでしょうか?

    現在はDBの接続文字列をweb.configに持っているのですが、
    リーダーの考えでINIファイルに持たせることになりました。


    この説明だけだと INI ファイルをどこに置こうとしているかが分からないので、一応の確認です。

    私がリーダーにそういう指示(各クライアントに INI ファイル)を受けたとしたら、どういう方法で実装したらよいかを **技術的に** 問い詰めると思います。
    Web サービスが DB の接続先を変更したいと思ったら、全部のクライアントを設定して回らないといけなくなりますし。
    2011年8月5日 5:26
  • タイトルがおかしくない?

    「クライアントからサーバに対して、DB 接続文字列を渡したい」わけじゃないですよね?

    実現したいのは、既に↑のような実装があって、「(サーバ上の Web.config と同じ(ような)場所に配置された).ini ファイルに書かれた DB 接続文字列を、↑の実装を大きく変えることなく web.config に書かれた DB 文字列と同じように利用したい」とかなのでは?

    2011年8月5日 5:26
    モデレータ
  • totojoさんへ

    すいません。言葉足らずでした。

    iniファイルは個々のクライアントに持たせてる方法です。


    2011年8月5日 6:07
  • 渋木さんへ

    すいません。そうです。

    クライアントのiniファイルにあるDB接続文字列を使用し、現状の実装を大きく変更しない方法です。

    サーバ上の Web.configで記述しているDB接続文字列を使用しないということです。


    2011年8月5日 6:12
  • かずきさんへ

    ありがとうございます。

    私がしたかったイメージですが、
    クライアント側でSysDate sd = new SysDate();
    の処理の時に引数として接続文字列を渡して、

    WebService側のpublic SysDate ()
    で引数の接続文字列をPrivateの変数に格納して
    ここの処理で使用できればと思っていたのです。

    2011年8月5日 6:14
  • > リーダーの考えでINIファイルに持たせることになりました。

    理由が不明ですが、なにか思い違いされてないでしょうか? 接続文字
    列が connectionStrings 要素ではなくて appSettings 要素にあるのを
    みても正しいやり方になっていないような感じがするのですが。

    > ConfigurationManager.AppSettings["DBConnString"];

    もし、セキュリティの問題を考えておられるなら web.congfig の
    connectionStrings 要素において、暗号化するというのが普通だと思い
    ます。

    接続文字列と構成ファイル (ADO.NET)
    http://msdn.microsoft.com/ja-jp/library/ms254494.aspx

     

    2011年8月5日 13:31
  • >すいません。そうです。

    「そう」じゃないようですね。

    僕が↑で書いた

    >「(サーバ上の Web.config と同じ(ような)場所に配置された).ini ファイルに書かれた DB 接続文字列を、↑の実装を大きく変えることなく web.config に書かれた DB 文字列と同じように利用したい」

    >クライアントのiniファイルにあるDB接続文字列を使用し、現状の実装を大きく変更しない方法です。

    とは異なります。(ざっくり言って逆)

    実現したいのは、totojo さんが↑で書いている

    >リーダー様の考えは、INI ファイルを各クライアントに持たせて、各クライアントから DB 接続文字列を指定しろ、ということなのでしょうか?

    ってことになりますね。

    限られた範囲で使える社内ツールならともかく、普通はこんな事(=生の接続文字列をクライアントからサーバに送り込んで、それをサーバで使う)しないですね。

    処理対象の「データ」ではなく「設定」をサーバに送り込むのは、セキュリティレベルを保つのが難しくなるなど、良くない面の方が気になります。

    「設定」の使われ方によってはサーバのクラッシュや情報漏えいが発生しかねませんと思えるのですが、そういった方面に関しては検討済みなんでしょうか?

     

     

    2011年8月6日 3:21
    モデレータ
  • 接続文字列をクライアントのINIに書く=クライアントはDBのアドレスを知っている

    なのだから、クライアントはサーバーに接続しなくても、直接DBに接続すればいいのに…

    • 回答の候補に設定 山本春海 2011年8月16日 7:05
    • 回答としてマーク 山本春海 2011年8月23日 6:26
    2011年8月6日 3:45
  • クライアント側に DB 接続文字列を持たせるということは、「Web サービスの実装内容をクライアントが意識しなくてよい」「Web サービスが DB を使用していることすらクライアントが意識しなくてよい」「DB 接続の設定を局所化する」などといった、アプリケーションのレイヤー構造のメリットを壊してしまいますし、他の方々も指摘されている通り、DB 接続文字列がネットワーク上をバンバン流れるのはセキュリティ的にどうかとも思いますが、ちょっと違った反応をしてみます。(きっと何らかの事情で、そういう実装をせざるを得ないのだろう、と好意的に解釈してみます。)

    # 本当は、なぜ各クライアントに DB 接続文字列を持たせようとするに至ったのか、リーダーの考えを知りたいところですが。
    # もしリーダーが間違った道に進もうとしているのであれば、それを羽交い絞めにしてでも思いとどまらせるのがメンバーの務めだとは思う。

    WebService側のpublic SysDate ()
    で引数の接続文字列をPrivateの変数に格納して
    ここの処理で使用できればと思っていたのです。


    Web サービスはステートレスでなければいけないので、private 変数に状態を保持してはダメです。
    SysDate sd = new SysDate();
    Label1.Text = sd.GetSysDate();
    Label2.Text = sd.GetSysDateStirng();


    同じインスタンスを使用しているように見えるかもしれませんが、Web サービスは別のインスタンスになります。次の記事が分かりやすいです。

    Webサービスのメソッド間でデータを共有する方法―日経ソフトウエア 2002年12月号特集2関連記事
    http://www15.nikkeibp.co.jp/software/special/200212toku2/0212tk2a.html

    Web サービスの間で状態を保持するには、最初に かずき_okazuki さんが回答されているような Session を使う方法しかないと思います。

    方法 : ASP.NET を使用して作成した Web サービスで状態を管理する
    http://msdn.microsoft.com/ja-jp/library/hk34sw2t.aspx

    なのですが、今回のケースですと

    ・ConfigurationManager 経由で DB 接続文字列を取得している部分を全部書き換えないといけない
    ・Session 変数には状態が変化するような揮発性の情報を入れるのが一般的
    ・Session が切れることの考慮も一応しておきたい

    と思いますので、DB 接続文字列のような固定の情報は、各 Web サービス メソッドの引数として渡してしまうのがスッキリすると思います。
    (佐祐理 さんの回答のように、そもそも Web サービスを使わないという意見が一番スッキリするのかも。)

    # クライアントが DB 接続文字列を引き渡すことに反対派であることに変わりはないです。
    • 回答の候補に設定 山本春海 2011年8月16日 7:05
    • 回答としてマーク 山本春海 2011年8月23日 6:26
    2011年8月7日 2:34
  • 元々は一般的なWebサービスとして構築されていたのを、わざわざクライアントにiniファイルを持たせるという特殊な実装に変更したいということですので、何か特別な考えがあってのことだろうと想像しますが、その理由によっては他に良い方法があるかもしれません。
    その理由がわからないので何とも言えませんが、どうしても今回のパターンで改修量を抑えたいのであれば、例えば接続文字列を与えなかった場合のデフォルトの接続文字列をWebサービス側に持つなどがあると思います。

     


    ★良い回答には回答済みマークを付けよう! わんくま同盟 MVP - Visual C# http://d.hatena.ne.jp/trapemiya/
    2011年8月7日 3:01
    モデレータ
  • 色々な意見ありがとうございます。

    やはり、セキュリティ上Web.configに持たせるのが
    一番だと皆さんのコメントを見て、感じました。

    クライアントのiniファイルに持たせる経緯ですが、
    現在、画面1つに対して、1つのWebServiceが
    存在しています。
    画面が100本くらいあるシステムのため、
    100本のWebServiceがあるのです。ということは
    100本のWeb.configがあり、そこに接続文字列が
    あります。本番環境にリリースする時に100個所の
    接続文字列を修正するのは時間がかかり、また、
    修正漏れが発生するため、クライアントのiniファイルに
    持たす話になりました。
    以前、1画面、1WebServiceの話が上がった時、
    私は1つのWebServiceを用意して、各画面単位で
    csファイルとasmxファイルを用意する方法を
    提案したのですが、却下された経緯があり、
    今の複数WebServiceがある状態になっています。

    今回の話を元にもう一度、リーダーに良い
    方法を提案しようと思います。

    また、何かあれば、ご指導お願いします。

    ありがとうございました。

    2011年8月8日 0:45
  • 1画面1WebServiceはいいとして、それでなぜweb.configが画面数ぶんあるのかわかりません・・・。もしかして、1画面1Webアプリケーション(そしてこのWebアプリの中に1サービスがある)なのでしょうか。

    普通は1つのWebアプリケーション内にWebサービスを複数配置して、web.configに接続文字列を格納しておくのが一般的だと思います。

    もし、1画面1Webアプリケーションだとした場合ですがweb.configは1つにしておいて各Webアプリケーションにリンクとしてweb.configを追加したりできないでしょうか。そうすれば、1つのweb.configをメンテするだけで大丈夫だと思います。


    かずき Blog:http://d.hatena.ne.jp/okazuki/ VS 2010のデザイナでBlendのBehaviorをサポートするツール公開してます。 http://vsbehaviorsupport.codeplex.com/
    • 回答の候補に設定 山本春海 2011年8月16日 7:05
    • 回答としてマーク 山本春海 2011年8月23日 6:26
    2011年8月8日 1:13
  • 画面が100本くらいあるシステムのため、
    100本のWebServiceがあるのです。ということは
    100本のWeb.configがあり、そこに接続文字列が
    あります。


    一斉につっこまれそうな話ですが、あえて触れずにおくとして。

    各 Web サービスの Web.config では接続文字列を書かないでおいて、Web サイトレベル (wwwroot の Web.config) に接続文字列を書けばいいように思います。試してはないですが。
    Machine.config に書いてしまうのは、ちとやりすぎかな。

    [INFO] ASP.NET の構成の概要
    http://support.microsoft.com/kb/307626/ja

    Web.config が 100 個なんて、尋常な話とは思えないですけれども。
    • 回答の候補に設定 山本春海 2011年8月16日 7:05
    • 回答としてマーク 山本春海 2011年8月23日 6:28
    2011年8月8日 1:32
  • 画面が100本くらいあるシステムのため、
    100本のWebServiceがあるのです。ということは
    100本のWeb.configがあり、そこに接続文字列が
    あります。本番環境にリリースする時に100個所の
    接続文字列を修正するのは時間がかかり、また、
    修正漏れが発生するため、クライアントのiniファイルに
    持たす話になりました。

    これ、クライアントが 200 台あったら、200か所のINIファイルを修正しないといけないですよね…。

    単純に、階層上で親になる web.config 1つに書けば、子階層にある 100 個の web.config には書かないでもよいと思います。最悪でも、サーバ側に INI ファイル1つを置いて、サーバ側で web.config のかわりに、その INI ファイルを見ればよいんじゃないかと思いますが…。(web.config と違って、INI ファイルは書き換えてもサービスを再起動してくれないので、そのあたりの仕組み作りが大変だとは思いますけど)

     

    • 回答の候補に設定 山本春海 2011年8月16日 7:05
    • 回答としてマーク 山本春海 2011年8月23日 6:27
    2011年8月8日 3:31
  • 以前、1画面、1WebServiceの話が上がった時、
    私は1つのWebServiceを用意して、各画面単位で
    csファイルとasmxファイルを用意する方法を
    提案したのですが、却下された経緯があり、
    今の複数WebServiceがある状態になっています。

    明らかにリーダーに致命的な欠陥があります。まずリーダーの改修方法を検討することをお勧めします。

    少なくともリーダー自らが責任を持ってweb.configの修正を行うべきかと。

    2011年8月8日 4:00
  • 先に紹介したページ、

    接続文字列と構成ファイル (ADO.NET)
    http://msdn.microsoft.com/ja-jp/library/ms254494.aspx

    の「外部構成ファイルの使用」のセクションに書いてあるように
    する手もあります。本番環境に移す時には、web.config を書き換
    えるのではなく、外部構成ファイルを差し替えるというのはいかが
    ですか?

     

    • 回答の候補に設定 山本春海 2011年8月16日 7:04
    • 回答としてマーク 山本春海 2011年8月23日 6:27
    2011年8月8日 13:06
  • 数々のアドバイスありがとうございます。

    リーダーと話あった結果、DB接続文字列を持ったiniファイルをサーバーにおいて、

    各WEBサービスはサーバーのiniファイルを読込む対応をすることで

    話がつきました。

    返信が遅くなり申し訳ありませんでした。

    また、ご教授お願いします。

    2011年8月11日 10:12