.net core并發(fā)下線程安全問題詳解
抱歉,其實內(nèi)容并不如題?。?!
背景(寫測試demo所出現(xiàn)的異常,供大家學(xué)習(xí)與拍磚):
.net core webapi項目,做了一個授權(quán)的filter(真正的生產(chǎn)項目的話,JWT很棒),單個接口測試沒有問題,當(dāng)用前端在同一個頁面調(diào)用多個接口的時候,運行服務(wù),打開頁面,然后……Exceptions……(真正的開發(fā)中大家應(yīng)該也會遇到)
異常1:An attempt was made to use the context while it is being configured. A DbContext instance cannot be used inside OnConfiguring since it is still being configured at this point. This can happen if a second operation is started on this context before a previous operation completed. Any instance members are not guaranteed to be thread safe.
異常2:A second operation started on this context before a previous operation completed. Any instance members are not guaranteed to be thread safe.
異常3:Invalid attempt to call Read when reader is closed.
異常4:Unable to cast object of type 'System.Data.ProviderBase.DbConnectionClosedConnecting' to type 'System.Data.SqlClient.SqlInternalConnectionTds'.
異常5:Object reference not set to an instance of an object.
異常6:不允許啟動新事務(wù),因為有其他線程正在該會話中運行。
異常7:An error occurred while updating the entries. See the inner exception for details.
嘗試運行了N多遍,嗯,挺不穩(wěn)定的(代碼垃圾?。强纯串惓0?/p>
一看很容易理解:在前一個操作完成之前,在此上下文中啟動第二個操作。任何實例成員都不能保證是線程安全的。就是說,我在用這個上下文的時候,你來搶個屁……
這個可能發(fā)生在并發(fā)的情況下,同時使用了同一個上下文……那么打開一個頁面,為什么會同時使用同一個上下文呢?好吧,在這里要負(fù)荊請罪了(可以說是自己的問題)
我在Filter里面有查詢,用到數(shù)據(jù)庫上下文<DbContext> 。罪過咯,直接想在Filter里面過濾黑名單,所以查了數(shù)據(jù)庫(這個業(yè)務(wù)是不合理的,這是一個作死的行為,請謹(jǐn)慎看待,這里做學(xué)習(xí)討論之用)。
public class AuthFilterAttribute : ActionFilterAttribute
{
public override void OnActionExecuting(ActionExecutingContext context)
{
base.OnActionExecuting(context);
.....
//判斷是否在黑名單內(nèi)
var blackList = _app.GetBlackList();
......
}}
這里為什么用 ActionFilterAttribute ?是因為測試的時候要監(jiān)測一下接口運行的整個過程,So……
然后還有一些錯是:對象引用未設(shè)置為對象的實例。這個錯誤太常見,不就是對象為Null了嗎?但是,未實例化對象在業(yè)務(wù)邏輯上的情況太多了。我的應(yīng)該有:
1、沒有獲取到當(dāng)前對象,這是.net core,不是.net,不是因為沒有new對象。是注入中沒有注入成功,獲取注入后,沒有獲取到。(但我本來運行的好好的,是因為一下是打開對接的頁面才發(fā)生的問題,可以排除了)
2、本來已經(jīng)實例的對象被回收了……(這可能性嘛……有一定的可能,但發(fā)生在哪呢?)
找啊找,其實方向有了,但是自己卻沒想起來……
其實如果不確定的話,倒是可以先找找別人是怎么說的(不是為了裝X,找開發(fā)上的問題我是推薦 github 和 stackoverflow 的,大部分的問題都可以找到):
(1)異常 1 還有同樣 一條搜索結(jié)果


(2)異常 2

雖然以上找的不一定是真正的答案,至少提供了一個方向,并且你至少可以嘗試性地去解決一下。這里提供的方向其實很明確:
1、是否應(yīng)該使用 Scoped 和 Transient 的,你卻使用了 Singleton;
2、多線程中使用了 async 卻沒有配對的使用 await;
至少我找到的關(guān)鍵點是這兩個。
那怎么找到并解決這個問題呢,.net core都是注入的,當(dāng)然 AuthFilterAttribute 也是注入的。跑到 Startup一看,很明顯,問題出在哪里了 -- 單例!本應(yīng)該是Scoped模式的,卻用了單例。
那就將 AuthFilterAttribute 換一種注入模式就行啦。
改為

我使用的是Filter,F(xiàn)ilter有自己的生命周期,去確認(rèn)一下:Filter的官方文檔
看到一張圖?。。。ó?dāng)然你也可以細(xì)細(xì)研讀一下這個文檔)如下:

這還不明顯??。?!
Filter會被回收的?。?!這同樣解釋了 異常3、4、5、6、7所發(fā)生的原因。
OK,問題已經(jīng)解決了,這是在開發(fā)中遇到的問題,可以說是涉及到.net core 本身的運行機制。
我算是一個應(yīng)用型的程序員,喜歡在應(yīng)用中學(xué)習(xí)底層的東西。那么接下來當(dāng)然就可以擴展 Singleton、Scoped 和 Transient 等知識了。
總結(jié)
以上就是這篇文章的全部內(nèi)容了,希望本文的內(nèi)容對大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價值,謝謝大家對腳本之家的支持。
相關(guān)文章
關(guān)于ASP.NET頁面打印技術(shù)的常用方法總結(jié)
B/S結(jié)構(gòu)導(dǎo)致了Web應(yīng)用程序中打印的特殊性;程序運行在瀏覽器中,打印機在本地,而文件確可能在服務(wù)器上,導(dǎo)致了打印控制不是很靈活,接下來介紹幾種常見的打印技術(shù),感興趣的朋友可以了解下2013-01-01
.NET實現(xiàn)在網(wǎng)頁中預(yù)覽Office文件的3個方法
這篇文章主要介紹了.NET實現(xiàn)在網(wǎng)頁中預(yù)覽Office文件的3個方法,本文最終采用了ASPOSE+pdf2swf+FlexPaper的方式解決了這個需求,需要的朋友可以參考下2014-10-10
xls表格導(dǎo)入數(shù)據(jù)庫功能實例代碼
這篇文章介紹了xls表格導(dǎo)入數(shù)據(jù)庫功能實例代碼,有需要的朋友可以參考一下2013-10-10
使用asp.net的pageDataSource中時索引問題解決方法
當(dāng)前頁面在數(shù)據(jù)的除第一頁的任何一個頁面時,重新條件查詢并且是新條件的總頁數(shù)小于剛才查詢得到的頁碼時,就會出現(xiàn)“索引 20 不是為負(fù)數(shù),就是大于行數(shù)”的類似的錯誤2013-04-04
.net core webapi通過中間件獲取請求和響應(yīng)內(nèi)容的方法
這篇文章主要介紹了.net core webapi通過中間件獲取請求和響應(yīng)內(nèi)容的方法,本文通過實例代碼給大家介紹的非常詳細(xì),具有一定的參考借鑒價值,需要的朋友可以參考下2019-09-09
Web.config 和 App.config 的區(qū)別分析
Web.config 和 App.config 的區(qū)別分析,需要的朋友可以參考一下2013-05-05
asp.net LC.exe已退出代碼為 -1的原因分析及解決方法
錯誤“LC.exe”已退出,代碼為 -1。是VS2005,并且在項目中引用了第三方組件。2013-06-06

