HttpContext 来源(System.Web.HttpContext.Current值为null的问题)
轉(zhuǎn)大神文檔:https://www.cnblogs.com/linJie1930906722/p/5708966.html
ASP.NET提供了靜態(tài)屬性System.Web.HttpContext.Current,因此獲取HttpContext對(duì)象就非常方便了。也正是因?yàn)檫@個(gè)原因,所以我們經(jīng)常能見(jiàn)到直接訪問(wèn)System.Web.HttpContext.Current的代碼:
1 using System;2 using System.Collections.Generic;3 using System.Linq;4 using System.Web;5 6 namespace Test_HttpContext.Current7 {8 public class Test9 { 10 11 public Test() 12 { 13 string file =System.Web.HttpContext.Current.Request.MapPath("~/App_Data/1.xml"); 14 15 string text = System.IO.File.ReadAllText(file); 16 17 //..........其它的操作 18 } 19 20 // 或者在一些方法中直接使用HttpContext.Current 21 public void Test_1() 22 { 23 string url = System.Web.HttpContext.Current.Request.RawUrl; 24 25 string username = System.Web.HttpContext.Current.Session["username"].ToString(); 26 27 string value = (string)System.Web.HttpContext.Current.Items["key"]; 28 } 29 30 // 甚至還設(shè)計(jì)成靜態(tài)屬性 31 public static string Test_2 32 { 33 get 34 { 35 return (string)System.Web.HttpContext.Current.Items["XXX"]; 36 } 37 } 38 39 /// <summary> 40 /// 獲取文件絕對(duì)路徑 41 /// </summary> 42 /// <param name="fileName">文件名稱</param> 43 /// <returns></returns> 44 public string Test_3(string fileName) 45 { 46 return System.Web.HttpContext.Current.Server.MapPath("~/Log" + fileName); 47 } 48 49 } 50 }上面的這些代碼這樣寫真的沒(méi)有問(wèn)題嗎?
答案是否定的
請(qǐng)看下面的驗(yàn)證:
我們先來(lái)看看HttpContext到底存儲(chǔ)在哪里:
1 using System;2 using System.Collections.Generic;3 using System.Linq;4 using System.Web;5 using System.Web.UI;6 using System.Web.UI.WebControls;7 8 namespace Test_HttpContext.Current9 { 10 public partial class WebForm1 : System.Web.UI.Page 11 { 12 protected void Page_Load(object sender, EventArgs e) 13 { 14 15 HttpContext context1 = System.Web.HttpContext.Current; 16 17 HttpContext context2 = System.Runtime.Remoting.Messaging.CallContext.HostContext as HttpContext; //當(dāng)前(請(qǐng)求)線程上下文 18 19 bool isEqual = object.ReferenceEquals(context1, context2); 20 21 Response.Write("context1與context2是否相同的實(shí)例:" + isEqual); 22 } 23 } 24 }上面的代碼運(yùn)行的結(jié)果是true:
從這段代碼來(lái)看,HttpContext其實(shí)是保存在System.Runtime.Remoting.Messaging.CallContext.HostContext這個(gè)屬性中, System.Runtime.Remoting.Messaging.CallContext.HostContext在MSDN的解釋是 獲取或設(shè)置與當(dāng)前線程相關(guān)聯(lián)的主機(jī)上下文
我們?cè)谝粋€(gè)ASP.NET程序中,為什么可以到處訪問(wèn)HttpContext.Current呢?
因?yàn)锳SP.NET會(huì)為每個(gè)請(qǐng)求分配一個(gè)線程(也是當(dāng)前線程),這個(gè)線程會(huì)執(zhí)行我們的代碼來(lái)生成響應(yīng)結(jié)果, 即使我們的代碼散落在不同的地方(類庫(kù)),線程仍然會(huì)執(zhí)行它們, 所以我們可以在任何地方訪問(wèn)System.Web.HttpContext.Current獲取到與當(dāng)前請(qǐng)求相關(guān)的HttpContext對(duì)象, 這些代碼是由同一個(gè)線程來(lái)執(zhí)行,所以得到的HttpContext引用也就是我們期待的那個(gè)與請(qǐng)求相關(guān)的對(duì)象。
當(dāng)前線程是什么意思??
我的理解是:
1. 當(dāng)前線程是指與當(dāng)前請(qǐng)求相關(guān)的線程。
2. 在ASP.NET程序中,有些線程并非總是與請(qǐng)求相關(guān)。
雖然在ASP.NET程序中,幾乎所有的線程都應(yīng)該是為響應(yīng)請(qǐng)求而運(yùn)行的,但是還有一些線程卻不是為了響應(yīng)請(qǐng)求而(產(chǎn)生)運(yùn)行的,
例如:
1. 定時(shí)器的回調(diào)。
2. Cache的移除通知。
3. APM模式下異步完成回調(diào)。
4. 主動(dòng)創(chuàng)建線程或者將任務(wù)交給線程池來(lái)執(zhí)行。
5.異步任務(wù)Task
至于什么APM網(wǎng)上資料很多,這里我就不說(shuō)明了
在這些情況下使用System.Web.HttpContext.Current獲取HttpContext對(duì)象得到的結(jié)果都是null,因?yàn)樘幚硭麄兊木€程不是當(dāng)前線程(為處理請(qǐng)求產(chǎn)生線程)
說(shuō)的這里我們?cè)倩仡^看看本文開(kāi)始寫的(部分)代碼:
1 /// <summary> 2 /// 獲取文件絕對(duì)路徑 3 /// </summary> 4 /// <param name="fileName">文件名稱</param> 5 /// <returns></returns> 6 public string Test_3(string fileName) 7 { 8 return System.Web.HttpContext.Current.Server.MapPath("~/Log" + fileName); 9 }如果這段代碼在那5種情況下運(yùn)行,都會(huì)拋空指針異常,因?yàn)镾ystem.Web.HttpContext.Current得到是null。
為什么會(huì)得到null呢?
因?yàn)檫\(yùn)行這段代碼線程不是處理當(dāng)前請(qǐng)求的當(dāng)前線程
為什么其他地方得到又不是null呢?
因?yàn)锳SP.NET程序在調(diào)用您的代碼前,已經(jīng)將HttpContext對(duì)象設(shè)置到前面所說(shuō)的System.Runtime.Remoting.Messaging.CallContext.HostContext屬性中。
HttpApplication有個(gè)內(nèi)部方法OnThreadEnter(),ASP.NET在調(diào)用外部代碼前會(huì)調(diào)用這個(gè)方法來(lái)切換HttpContext, 例如:每當(dāng)執(zhí)行管線的事件處理器之前,或者同步上下文(AspNetSynchronizationContext)執(zhí)行回調(diào)時(shí)。 切換線程的CallContext.HostContext屬性之后,我們的代碼就可以訪問(wèn)到HttpContext引用。 注意:HttpContext的引用其實(shí)是保存在HttpApplication對(duì)象中。
?
這種情況下該如何獲取文件的絕對(duì)路徑呢?
我們可以訪問(wèn)System.Web.HttpRuntime.AppDomainAppPath獲取程序的根路徑,然后再拼接文件的相對(duì)路徑即可
上面的代碼得到的HttpContext對(duì)象是null,再調(diào)用MapPath來(lái)獲取站點(diǎn)根目錄,就必死無(wú)疑了!
所以在此建議大家在獲取程序(站點(diǎn))的根目錄時(shí)盡量使用System.Web.HttpRuntime.AppDomainAppPath進(jìn)行獲取站點(diǎn)的根目錄
?
那么在異步調(diào)用調(diào)用時(shí)訪問(wèn)HttpContext對(duì)象呢?
前面我還提到在APM模式下的異步完成回調(diào)時(shí),訪問(wèn)HttpContext.Current也會(huì)返回null,那么此時(shí)該怎么辦呢?
1. 在類型中添加一個(gè)字段來(lái)保存HttpContext的引用(異步開(kāi)始前)。
2. 將HttpContext賦值給BeginXXX方法的最后一個(gè)參數(shù)(object state)
建議優(yōu)先選擇第二種方法,因?yàn)榭梢苑乐挂院笏司S護(hù)時(shí)數(shù)據(jù)成員被意外使用。
?
轉(zhuǎn)載于:https://www.cnblogs.com/janeaiai/p/8794066.html
總結(jié)
以上是生活随笔為你收集整理的HttpContext 来源(System.Web.HttpContext.Current值为null的问题)的全部?jī)?nèi)容,希望文章能夠幫你解決所遇到的問(wèn)題。
- 上一篇: DataBinding 学习系列(2)详
- 下一篇: 快速查看Gradle项目的类库依赖情况