今天在對(duì)項(xiàng)目代碼進(jìn)行異步化改進(jìn)的時(shí)候,遇到一個(gè)奇怪的問題(莫笑,以前沒遇過),正如標(biāo)題一樣,HttpContext.Current 在 await 異步執(zhí)行之后,就會(huì)變?yōu)?null。
演示代碼:
public async Task<IEnumerable<string>> Get() { await DoWaitAsync(); DoWork(); return new string[] { "value1", "value2" }; } PRivate Task DoWaitAsync() { return Task.Factory.StartNew( () => { // null !! var httpCtx = System.Web.HttpContext.Current; Thread.Sleep(1000); }); } public void DoWork() { //Not null var httpCtx = System.Web.HttpContext.Current; }
HttpContext.Current 這個(gè)東西,我們并不陌生,在進(jìn)行 asp.net 應(yīng)用程序開發(fā)的時(shí)候,我們經(jīng)常會(huì)用到,比如獲取當(dāng)前請(qǐng)求的一些值,首先它是一個(gè)線程靜態(tài)屬性(thread-static variable),注意其中的關(guān)鍵字:當(dāng)前請(qǐng)求和線程,也就是說它是和請(qǐng)求線程相關(guān)的,在 ASP.NET 應(yīng)用程序中,一個(gè)請(qǐng)求線程會(huì)貫穿整個(gè)請(qǐng)求過程,所以我們可以在這個(gè)請(qǐng)求的任何地方,都可以訪問到 HttpContext.Current,這也就是它的“強(qiáng)大之處”,但是如果涉及到異步多線程呢?就不是這么回事了,因?yàn)?HttpContext.Current 依附的是當(dāng)前請(qǐng)求的主線程,當(dāng)我們使用 await 異步執(zhí)行一些代碼的時(shí)候,再次執(zhí)行下面的代碼,其實(shí)就不是當(dāng)前請(qǐng)求線程了,所以我們?cè)俅卧L問 HttpContext.Current 的時(shí)候,就變?yōu)?null 了,這個(gè)問題告誡我們,ASP.NET 應(yīng)用程序中,如果進(jìn)行異步化,使用 HttpContext.Current 一定要小心謹(jǐn)慎。
如果我們的 ASP.NET 應(yīng)用程序進(jìn)行了異步化,然后還必須用到 HttpContext.Current,那我們?cè)撛趺唇鉀Q這個(gè)問題?
解決的方式有很多,如果應(yīng)用程序很簡(jiǎn)單,我們可以在 await 操作之前,先用變量存儲(chǔ) HttpContext.Current,用到的地方直接用這個(gè)變量就行了,當(dāng)然這不是一個(gè)“解決問題”的方法,還有一種是用 Cache,可以參考:system-web-httpcontext-current-nulls-itself-after-checking-for-a-cache,我覺得這種方式也是“瞎忽悠”,沒有從根本問題上進(jìn)行解決。
其實(shí)想想問題的根源,就是如何在多個(gè)線程中共享一個(gè) HttpContext.Current,這個(gè)在 MSDN 中表述為:共享/同步上下文(Synchronization Context)
You can use the TaskScheduler.FromCurrentSynchronizationContext method to specify that a task should be scheduled to run on a particular thread. This is useful in frameworks such as Windows Forms and Windows Presentation Foundation where access to user interface objects is often restricted to code that is running on the same thread on which the UI object was created. For more information, see How to: Schedule Work on a Specified Synchronization Context.
那我們?nèi)绾卧?ASP.NET 應(yīng)用程序中,進(jìn)行運(yùn)用呢?答案很簡(jiǎn)單,我們只需要在 web.config 中指定 targetFramework 版本為 4.5 即可:
<httpRuntime targetFramework="4.5" />
或者在 appSettings 中添加如下 key(測(cè)試可用):
<add key="aspnet:UseTaskFriendlySynchronizationContext" value="true" />
參考資料:
|
新聞熱點(diǎn)
疑難解答
圖片精選
網(wǎng)友關(guān)注