トップ回答者
DB接続文字列をクライアントからWebServiceに渡す方法について

質問
-
はじめまして
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接続情報を追加すればいいのはわかるのですが、
既に多くの画面を開発していて、
修正にかなりの時間がかかります。修正個所を最小限にする方法があれば、
ご教授ください。お願いします。
回答
-
クライアント側に 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 接続文字列を引き渡すことに反対派であることに変わりはないです。 -
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/ -
画面が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 個なんて、尋常な話とは思えないですけれども。 -
画面が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 ファイルは書き換えてもサービスを再起動してくれないので、そのあたりの仕組み作りが大変だとは思いますけど)
すべての返信
-
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/ -
リーダー様の考えは、INI ファイルを各クライアントに持たせて、各クライアントから DB 接続文字列を指定しろ、ということなのでしょうか?
それとも単に、Web.config でなく DB 接続文字列だけ INI ファイルに分離して、サーバーのどこかに置いておけ、ということなのでしょうか?
現在はDBの接続文字列をweb.configに持っているのですが、
リーダーの考えでINIファイルに持たせることになりました。
この説明だけだと INI ファイルをどこに置こうとしているかが分からないので、一応の確認です。
私がリーダーにそういう指示(各クライアントに INI ファイル)を受けたとしたら、どういう方法で実装したらよいかを **技術的に** 問い詰めると思います。
Web サービスが DB の接続先を変更したいと思ったら、全部のクライアントを設定して回らないといけなくなりますし。 -
> リーダーの考えでINIファイルに持たせることになりました。
理由が不明ですが、なにか思い違いされてないでしょうか? 接続文字
列が connectionStrings 要素ではなくて appSettings 要素にあるのを
みても正しいやり方になっていないような感じがするのですが。> ConfigurationManager.AppSettings["DBConnString"];
もし、セキュリティの問題を考えておられるなら web.congfig の
connectionStrings 要素において、暗号化するというのが普通だと思い
ます。接続文字列と構成ファイル (ADO.NET)
http://msdn.microsoft.com/ja-jp/library/ms254494.aspx -
クライアント側に 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 接続文字列を引き渡すことに反対派であることに変わりはないです。 -
元々は一般的なWebサービスとして構築されていたのを、わざわざクライアントにiniファイルを持たせるという特殊な実装に変更したいということですので、何か特別な考えがあってのことだろうと想像しますが、その理由によっては他に良い方法があるかもしれません。
その理由がわからないので何とも言えませんが、どうしても今回のパターンで改修量を抑えたいのであれば、例えば接続文字列を与えなかった場合のデフォルトの接続文字列をWebサービス側に持つなどがあると思います。
★良い回答には回答済みマークを付けよう! わんくま同盟 MVP - Visual C# http://d.hatena.ne.jp/trapemiya/ -
色々な意見ありがとうございます。
やはり、セキュリティ上Web.configに持たせるのが
一番だと皆さんのコメントを見て、感じました。クライアントのiniファイルに持たせる経緯ですが、
現在、画面1つに対して、1つのWebServiceが
存在しています。
画面が100本くらいあるシステムのため、
100本のWebServiceがあるのです。ということは
100本のWeb.configがあり、そこに接続文字列が
あります。本番環境にリリースする時に100個所の
接続文字列を修正するのは時間がかかり、また、
修正漏れが発生するため、クライアントのiniファイルに
持たす話になりました。
以前、1画面、1WebServiceの話が上がった時、
私は1つのWebServiceを用意して、各画面単位で
csファイルとasmxファイルを用意する方法を
提案したのですが、却下された経緯があり、
今の複数WebServiceがある状態になっています。今回の話を元にもう一度、リーダーに良い
方法を提案しようと思います。また、何かあれば、ご指導お願いします。
ありがとうございました。
-
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/ -
画面が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 個なんて、尋常な話とは思えないですけれども。 -
画面が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 ファイルは書き換えてもサービスを再起動してくれないので、そのあたりの仕組み作りが大変だとは思いますけど)