簡體   English   中英

在ASP.NET中正確地放置SqlConnection?

[英]Properly disposing a SqlConnection in ASP.NET?

我有一個使用SqlConnection來連接到數據庫的ASP.NET Web API。 我有一個數據訪問層類,該類具有包含連接的實例變量。 我這樣做有兩個原因:

  1. 調用代碼可以覆蓋DAL類的構造函數中的連接字符串(例如,用於測試代碼)
  2. 在某些情況下,API控制器需要打開SQL連接,開始事務,然后在提交(或回滾)事務之前調用DAL類中的多個方法。 因此,關閉和重新打開每個方法的連接將不起作用,因為我必須保持連接處於打開狀態(甚至將SqlTransaction對象保持在作用域內-我會通過使其也成為實例變量來做到這一點),以便不具有事務在DAL調用之間回滾。
  3. 它還簡化了代碼的可讀性,因此您不必在各處復制代碼來打開SQL連接。

當我對API進行壓力測試時,通過每秒提供數百個請求,我遇到了SQL連接池耗盡的問題。 進一步的調查表明,這似乎是因為未處理SQL連接。

我確實了解IDisposable模式,但不確定在這種情況下如何使用它。 這是我的問題:

  1. 使用using塊或try/catch/finally塊,都需要在單個方法中創建,使用和完成對象。 在上面的示例中,可能需要在多個方法調用之間保持持久的事務,這是不可能的。
  2. Microsoft(以及SO上的其他文章)建議不要在對象析構函數中簡單地調用Dispose() ,而建議您執行我在問題1中指定的任一選項。
  3. 微軟還說,您不應該自己實現IDisposable來包裝另一個管理對象的Dispose方法,而應該“在完成該對象后簡單地在該對象上調用Dispose()”。 當我不確定從DAL內部完成控制器使用SQL連接后,如何在這種情況下執行此操作? (此外,這意味着我必須重構控制器,以將對DAL的每個調用包裝在using塊中,因此它只是將罐子踢倒了。)

對我而言, 理想的解決方案是能夠以某種方式安排在控制器完成處理並將響應返回給服務器以傳遞到前端時,在SqlConnection對象上調用Dispose方法。 要“手動”執行此操作,我將不得不違反上面的第3點,並在DAL上創建自己的Dispose方法,該方法又反過來調用SqlConnection的Dispose 這也意味着我必須在所有控制器中重構許多方法,以將所有DAL訪問包裝在using塊中。 似乎當控制器返回時ASP.NET不會自動調用Dispose ,這就是連接泄漏的原因。

無論哪種情況,它都需要更多詳細的代碼。 例如:

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

現在必須寫成:

// 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);
}

推薦的實現方式是什么?

在更通用的層面上,您實際上如何處理必須在方法調用之間保留的一次性對象(例如,作為實例變量)? 在諸如try/catch/finally之類的構造中使用一次性用品或using似乎將它們的使用僅限於可以在單一方法中創建和處置對象的情況。

MSDN建議,您應該使用

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

注意:每次不會打開新連接

如果有連接,則SqlConnection從連接池中繪制一個打開的連接。 否則,它將建立與SQL Server實例的新連接。

並且為了控制您的交易-您可以只使用TransactionScope() (盡管在某些情況下可能需要MSDTC


否則,如果不是使用TransactionScope的選項,並且您想顯式控制您的事務,則唯一的選擇就是傳遞連接。 正如本POST中討論的那樣

您可以通過兩種方式進行“傳遞”。 手動或使用依賴注入( DI )。 所有的DI容器都允許您控制實例的生存期。 因此,在您的情況下,這可能是“ 每個請求生命周期 ”,可以在此帖子中找到一個示例

關於本段。

在更通用的層面上,您實際上如何處理必須在方法調用之間保留的一次性對象(例如,作為實例變量)? 在諸如try / catch / finally之類的構造中使用一次性用品或使用的需求似乎將它們的使用僅限於可以在單一方法中創建和處置對象的情況。

根據經驗,負責實例化一次性對象的方法應該是負責處理該對象的方法,可以將其作為參數傳遞給從實例化方法調用的其他方法,但是這些方法不應負責處理物體。 如果實例化要注入到另一個類中的對象,則可能是此規則的例外,但是在這種情況下,該類應具有IDisposable屬性,並且在使用后應由調用者處置。

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM