Cannot access a disposed object in ASP.NET Core
導航
- 常見原因
- 總結
對於.neter來說,在使用ASP.NET Core的過程中,大家或多或少會遇到這樣的報錯——“Cannot access a disposed object”。出現這樣的異常的原因有很多,如果它在調試的時候出現是很容易解決的,但是有些時候它在本地運行良好,等到你部署到生產環境才會表現出來。針對這個異常,請跟隨我一起來分析和探究其根本原因。
在ASP.NET Core開發中,我多次碰見了這樣的報錯,並且跟蹤這個bug很艱難。這樣的報錯有多種原因。有時僅憑其表現的“症狀”就能修復這個Bug,但是有時候又極其痛苦。通過尋找“病因”,我們可以反過來優化自己的代碼。
錯誤信息很清楚:
Cannot access a disposed object. A common cause of this error is disposing a context that was resolved from dependency injection and then later trying to use the same context instance elsewhere in your application. This may occur if you are calling Dispose() on the context, or wrapping the context in a using statement. If you are using dependency injection, you should let the dependency injection container take care of disposing context instances.
Object name: 'XXXContext'.
常見原因
對象已經釋放(The object is disposed in your code)
最簡單的原因是你有一個可以釋放的對象,然后你在代碼的某個地方釋放了它。也可能是你釋放了一個使用了該對象的對象。當你試圖訪問一個被釋放的對象時,就引發了該異常。此時,你要做的就是查看該范圍的代碼路徑,或者上下文調用關系,通過打斷點來排查該問題。
代碼異步執行(Some code is running async)
我遇到的另外一種原因是你在新線程中執行了某段邏輯。依賴的框架釋放了對象,並將該對象返回給主線程。
新的線程執行了已經釋放的對象,然后引發異常。要解決此問題.你必須單獨地開啟新線程來管理這個可以被釋放的對象。
Task.Run( () => { // or ThreadPool.QueueUserWorkItem(async _ => {
using (var context = **create your new context here, handle it directly or let the DI framework do its magic**){
foreach(var user in Users){
email.Send(user.email);
context.....;
context.SaveChanges();
}
}
});
在APS.NET Core Web API 中,我們可以用Swashbuckle.AspNetCore 和 NSwag這兩個包來實現Swagger,而且二者都是github上開源的。此外,nswag還提供了生成typescript客戶端代碼的方法以及用於API的服務代碼。
使用async void 而非 async Task
另一種原因可能是你在本應該使用使用async Task的地方使用了async void。潛在的異步代碼會在你的線程返回之后執行。就像在代碼中啟動一個新線程一樣,它可能會意外地正確運行。在這種情況下,您可能只在release版本中看到錯誤。當您不知道在哪里查找時,這可能很難調試。PS:筆者恰好遭遇該情況,我和我的小伙伴花費了一天時間來找這個bug。
錯誤的寫法:
public async void FailtyMethod(){
正確的寫法:
public async Task CorrectMethod(){
總結
解決這些bug,有時候會令人沮喪,甚至抓狂。我曾今和我的另外兩個小伙伴花費了一天時間來找這個bug。最后大家都黔驢技窮。
我希望這篇文章能夠幫助到你。
參考
關注
請關注微信公眾號智客坊。