2017-05-31 9 views
0

私はSqlConnectionを使用してデータベースに接続するASP.NET Web APIを持っています。私は、接続を含むインスタンス変数を持つデータアクセス層クラスを持っています。 I理由のカップルのためにこれを行う:DALクラスのコンストラクタ内の接続文字列(テストコード用など) ASP.NETにSqlConnectionを適切に配置しますか?

  • を上書きすることができます

    1. 呼び出しコードAPIコントローラを開く必要が場合がありますSQL接続を開始し、トランザクションを開始してから、トランザクションをコミットする(またはロールバックする)前に、DALクラス内のいくつかのメソッドを呼び出します。だから、コネクションを開いたままにしておく必要があるため、メソッドごとにコネクションを閉じて再オープンすることはできません(また、SqlTransactionオブジェクトをスコープに入れておく必要があります。トランザクションはDALコール間でロールバックされます。
    2. これはまた、コードの読みやすさを簡素化するので、SQL接続を開くための場所全体にコードを複製しているわけではありません。

    私のAPIをストレステストしたところ、毎秒何百ものリクエストを与えることで、SQL接続プールの枯渇という問題にぶつかりました。さらに調査すると、これはSQL接続が処分されていないためであると思われます。

    私はIDisposableパターンを理解していますが、このシナリオでどのように使用するかはわかりません。ここに私の問題だ:

    1. usingブロック、またはtry/catch/finallyブロックを使用して、両方のは、オブジェクト、作成に使用して、単一のメソッド内で確定することが必要です。上記の例では、複数のメソッド呼び出しにまたがって持続する必要のあるトランザクションは不可能です。
    2. マイクロソフト(およびSO上の他の記事は)単純に代わり示唆、オブジェクトのデストラクタでDispose()に電話を入れて反対をお勧めしていますが、私は問題で指定されたオプションのいずれかを実行し、Microsoftはまた、あなたが実装するべきではないと言う。1.
    3. IDisposable自分で別の管理オブジェクトのDisposeメソッドをラップするだけで済みますが、オブジェクトを終了したら「単にDispose()を呼び出す」必要があります。コントローラがSQL接続の使用を終了したときに、DALの中からわからないときは、このシナリオでどのようにしたらいいですか? (また、これはそれだけで道缶を蹴っていますので、私は、usingブロックにDALへの各呼び出しをラップするようにコントローラをリファクタリングする必要が意味します。)

    私にとって理想的なソリューションは次のようになりコントローラーが処理を終了し、サーバーへの応答をフロントエンドに渡すために返すときに、SqlConnectionオブジェクトで呼び出されたDisposeメソッドを何らかの形で整理できるようにするためです。これを「手作業で」行うには、上記のポイント3に違反し、私のDAL上に独自のDisposeメソッドを作成して、単にSqlConnectionのDisposeを呼び出す必要があります。また、すべてのコントローラで多くのメソッドをリファクタリングして、すべてのDALアクセスをusingブロックにラップする必要があることを意味します。コントローラが復帰したときにASP.NETが自動的にDisposeを呼び出すことはないため、接続が漏れているようです。

    いずれの場合も、より冗長なコードになります。たとえば:

    // we have to initialize here to keep the variable from falling out of scope after the using blocks 
    // we also must provide some value because the using block implies try/catch. 
    string someData = ""; 
    using (DAL d = new DAL()) { 
        someData = d.getSomeData(someParam); 
    } 
    

    は何これを実装するために推奨される方法のようになります。

    // we only need one method call from the DAL, so let's be compact 
    string someData = new DAL().GetSomeData(someParam); 
    

    今のように書かれなければなら?

    より一般的なプレーンでは、メソッド呼び出し(インスタンス変数など)の間に存続する必要がある使い捨てオブジェクトを実際にどのように処理しますか? try/catch/finallyまたはusingのような構造内でディスポーザブルを使用する必要性は、オブジェクトを作成して1つのメソッド内に配置できる状況にのみ使用を制限するようです。

  • +1

    DIコンテナを使用している場合は、リクエストが終了したときにリソースを廃棄することができます。私は個人的にコネクションを自分で管理することを好みますが、必要なときに開いて、やってみましょう。 – Evk

    答えて

    0

    MSDN recommendsとして、あなたは

    using(var cn = new SqlConnection(xx)){ cn.Open(); }

    NOTEを使用する必要があります。 が1であれば、それは、新しい接続に

    SqlConnectionオブジェクトは、接続プールからオープン接続を描画するたびに開きません利用可能です。それ以外の場合は、 SQL Serverのインスタンスに新しい接続を確立します。

    そして、あなたの取引をcontrollするために - (それはMSDTC in some case`sを必要とするかもしれないが)TransactionScopeを使用すると、オプションではありません、そしてあなたが明示的に制御したい場合は、単に、そうでない場合


    TransactionScope()を使用することができますあなたのトランザクション、唯一のオプションは、接続を渡すことです。それはそのままですdiscussed in this POST

    「通過」は2通りの方法で行うことができます。手動で、または依存性注入(DI)を使用してください。すべてのDIコンテナによって、インスタンスのの有効期間を制御することができます。だからあなたのケースでは、この段落についてサンプルがthis post

    +0

    これはほとんどの場合当然ですが、接続文字列が接続プールを無効にしないようにする必要がありますが、これはデフォルトの動作ではありませんが、発生する可能性があります。 – Zalomon

    +0

    これらの答えに基づいて、少なくともTransactionScopeなしでこれを行う方法はないと思われます...これはあまりにも悪く、DALを別のクラスに分けるという全体のポイントを打ち負かしているようです。 Web APIが接続の作成と廃棄を管理するとすぐに、DALを分離する(たとえば、新しいDALを作成するだけでDBMSを置き換えることができ、テスト用に模擬DALを使用するなどしても)利点がありません。 DALを使い捨てにしてからDAL用のWeb APIで「使用する」ことをお勧めします。 – fdmillion

    +0

    あなたが参照している投稿には、私の正確な問題が書かれています:「仕事をしているクラスのメンバーに接続を昇格させることが役立つことがありますが、これは厄介な状況を招き、接続の寿命と処理を複雑にします(なぜなら、これは一般にusingステートメントの使用を排除するからです)。だから私がこれを行うことができる唯一の方法は、DALを使い捨てにして、各コントローラメソッドで 'using 'にラップすることです。 – fdmillion

    0

    で見つけることができ 「要求寿命あたり」かもしれません。

    もっと一般的なプレーンでは、メソッドコール(インスタンス変数など)の間に保持されなければならない使い捨てオブジェクトはどのように処理されますか? try/catch/finallyやuseのようなコンストラクト内でディスポーザブルを使用する必要性は、オブジェクトを作成して1つのメソッド内に配置できる状況にのみその使用を制限するようです。

    使い捨てオブジェクトのインスタンス化を担当するメソッドは、それを処理する責任があるはずですが、インスタンス化メソッドから呼び出される他のメソッドへの引数として渡しても構いませんが、これらのメソッドは、オブジェクトを廃棄する責任を負いません。このルールの例外は、オブジェクトをインスタンス化して別のクラスにインジェクトする場合ですが、この場合、このクラスはIDisposableを暗示する必要があり、使用後にインボーカが処理する必要があります。

    +0

    それは意味があります、私は使用している論理モデルに従っていません...上で述べたように、Web APIで 'SqlConnection'オブジェクトを作成してDALに渡すとすぐに、分離されたDAL(DALを置き換えるだけでDBMSを完全に置き換えることができます)。他のシナリオにも同じことが当てはまります。 DIは確かにその場所を持っていますが、時には "コンポーネント"のアイデアにも違反しています。この場合、データベースにアクセスするために必要なものすべてを提供するクラスが1つあります... – fdmillion

    +0

    IDは、 APIはDALの代わりにSQLConnectionをインスタンス化します。実際には、APIはSQLConnectionの存在について何も知らないはずです。接続が作成されて処理されるデータベースへの共通のエントリポイントが必要です – Zalomon

    関連する問題