ASP.NET提供了静态属性System.Web.HttpContext.Current,因此获取HttpContext对象就非常方便了。也正是因为这个原因,所以我们经常能见到直接访问System.Web.HttpContext.Current的代码:

 using System;
using System.Collections.Generic;
using System.Linq;
using System.Web; namespace Test_HttpContext.Current
{
public class Test
{ public Test()
{
string file =System.Web.HttpContext.Current.Request.MapPath("~/App_Data/1.xml"); string text = System.IO.File.ReadAllText(file); //..........其它的操作
} // 或者在一些方法中直接使用HttpContext.Current
public void Test_1()
{
string url = System.Web.HttpContext.Current.Request.RawUrl; string username = System.Web.HttpContext.Current.Session["username"].ToString(); string value = (string)System.Web.HttpContext.Current.Items["key"];
} // 甚至还设计成静态属性
public static string Test_2
{
get
{
return (string)System.Web.HttpContext.Current.Items["XXX"];
}
} /// <summary>
/// 获取文件绝对路径
/// </summary>
/// <param name="fileName">文件名称</param>
/// <returns></returns>
public string Test_3(string fileName)
{
return System.Web.HttpContext.Current.Server.MapPath("~/Log" + fileName);
} }
}

上面的这些代码这样写真的没有问题吗?
答案是否定的

请看下面的验证:

我们先来看看HttpContext到底存储在哪里:

 using System;
using System.Collections.Generic;
using System.Linq;
using System.Web;
using System.Web.UI;
using System.Web.UI.WebControls; namespace Test_HttpContext.Current
{
public partial class WebForm1 : System.Web.UI.Page
{
protected void Page_Load(object sender, EventArgs e)
{ HttpContext context1 = System.Web.HttpContext.Current; HttpContext context2 = System.Runtime.Remoting.Messaging.CallContext.HostContext as HttpContext; //当前(请求)线程上下文 bool isEqual = object.ReferenceEquals(context1, context2); Response.Write("context1与context2是否相同的实例:" + isEqual);
}
}
}

上面的代码运行的结果是true:

从这段代码来看,HttpContext其实是保存在System.Runtime.Remoting.Messaging.CallContext.HostContext这个属性中, System.Runtime.Remoting.Messaging.CallContext.HostContext在MSDN的解释是 获取或设置与当前线程相关联的主机上下文

我们在一个ASP.NET程序中,为什么可以到处访问HttpContext.Current呢?
因为ASP.NET会为每个请求分配一个线程(也是当前线程),这个线程会执行我们的代码来生成响应结果,
即使我们的代码散落在不同的地方(类库),线程仍然会执行它们,
所以我们可以在任何地方访问System.Web.HttpContext.Current获取到与当前请求相关的HttpContext对象, 这些代码是由同一个线程来执行,所以得到的HttpContext引用也就是我们期待的那个与请求相关的对象。

当前线程是什么意思?
我的理解是:
1. 当前线程是指与当前请求相关的线程。
2. 在ASP.NET程序中,有些线程并非总是与请求相关。

虽然在ASP.NET程序中,几乎所有的线程都应该是为响应请求而运行的,但是还有一些线程却不是为了响应请求而(产生)运行的,

例如:
1. 定时器的回调。
2. Cache的移除通知。
3. APM模式下异步完成回调。
4. 主动创建线程或者将任务交给线程池来执行。

5.异步任务Task

至于什么APM网上资料很多,这里我就不说明了

在这些情况下使用System.Web.HttpContext.Current获取HttpContext对象得到的结果都是null,因为处理他们的线程不是当前线程(为处理请求产生线程)

说的这里我们再回头看看本文开始写的(部分)代码:

          /// <summary>
/// 获取文件绝对路径
/// </summary>
/// <param name="fileName">文件名称</param>
/// <returns></returns>
public string Test_3(string fileName)
{
return System.Web.HttpContext.Current.Server.MapPath("~/Log" + fileName);
}

如果这段代码在那5种情况下运行,都会抛空指针异常,因为System.Web.HttpContext.Current得到是null。

为什么会得到null呢?

因为运行这段代码线程不是处理当前请求的当前线程

为什么其他地方得到又不是null呢?

因为ASP.NET程序在调用您的代码前,已经将HttpContext对象设置到前面所说的System.Runtime.Remoting.Messaging.CallContext.HostContext属性中。

HttpApplication有个内部方法OnThreadEnter(),ASP.NET在调用外部代码前会调用这个方法来切换HttpContext, 例如:每当执行管线的事件处理器之前,或者同步上下文(AspNetSynchronizationContext)执行回调时。 切换线程的CallContext.HostContext属性之后,我们的代码就可以访问到HttpContext引用。 注意:HttpContext的引用其实是保存在HttpApplication对象中。

这种情况下该如何获取文件的绝对路径呢?

我们可以访问System.Web.HttpRuntime.AppDomainAppPath获取程序的根路径,然后再拼接文件的相对路径即可

上面的代码得到的HttpContext对象是null,再调用MapPath来获取站点根目录,就必死无疑了!

所以在此建议大家在获取程序(站点)的根目录时尽量使用System.Web.HttpRuntime.AppDomainAppPath进行获取站点的根目录

那么在异步调用调用时访问HttpContext对象呢?

前面我还提到在APM模式下的异步完成回调时,访问HttpContext.Current也会返回null,那么此时该怎么办呢?
1. 在类型中添加一个字段来保存HttpContext的引用(异步开始前)。
2. 将HttpContext赋值给BeginXXX方法的最后一个参数(object state)

建议优先选择第二种方法,因为可以防止以后他人维护时数据成员被意外使用。

为什么获取的System.Web.HttpContext.Current值为null,HttpContext对象为null时如何获取程序(站点)的根目录的更多相关文章

  1. HttpContext.Current.Server.MapPath("/") 未将对象设置到对象的实例异常。

    多线程中的System.Web.HttpContext.Current.Server.MapPath("/") 多线程中Server.MapPath会失效... 网上找到几种解决方 ...

  2. HttpContext.Current.Server.MapPath("") 未将对象设置到引用的

    在多线程中使用该方法获取目录报错:未将对象设置到引用 #region 上传图片到腾讯 public async Task<Result> UploadImageToWX(string ba ...

  3. 在C#中,为什么大家用httpcontext.current,不直接用HttpContext

    HttpContext只是个类名,HttpContext.Current才是一个已实例化的对象..比如这样一个类: class A{ public static A Current{get;set;} ...

  4. 我所知道的HttpContext.Current

    在MVC中,HttpContext.Current是比较常见的对象,可以用它来进行Session,Cache等的保存等.但是它并不是无处不在的,下面就慢慢来揭开它的面纱. 当我们向服务端发送请求的时候 ...

  5. 2014-08-26 解决HttpContext.Current.Session在ashx文件中出现“未将对象引用设置到对象的实例”的问题

    今天是在吾索实习的第35天. 最近在使用HttpContext.Current.Session来获取Session["..."]的值时,常常会弹出错误——“未将对象引用设置到对象的 ...

  6. System.Web.Caching.Cache类 缓存 各种缓存依赖

    原文:System.Web.Caching.Cache类 缓存 各种缓存依赖 Cache类,是一个用于缓存常用信息的类.HttpRuntime.Cache以及HttpContext.Current.C ...

  7. System.Web.Caching.Cache类 缓存

    1.文件缓存依赖 public partial class _Default : System.Web.UI.Page { protected void Page_Load(object sender ...

  8. HttpContext.Current 的缺陷

    了解ASP.NET的开发人员都知道它有个非常强大的对象 HttpContext,而且为了方便,ASP.NET还为它提供了一个静态属性HttpContext.Current来访问它,今天的博客打算就从H ...

  9. HttpContext.Current并非无处不在

    阅读目录 开始 无处不在的HttpContext HttpContext.Current到底保存在哪里? HttpContext并非无处不在! 如何获取文件绝对路径? 异步调用中如何访问HttpCon ...

随机推荐

  1. 使用xtrabackup备份mysql数据库

    数据在一个企业里非常重要,因此经常需要备份数据库,确保出线故障时,可以立刻恢复数据到最新状态,目前常见的备份工具有mysqldump和xtrabackup,数据量较少时可以使用mysqldump,但随 ...

  2. 中国UTM分区

    高斯-克吕格投影是“等角横切圆柱投影”,投影后中央经线保持长度不变,即比例系数为1: UTM投影是“等角横轴割圆柱投影”,圆柱割地球于南纬80度.北纬84度两条等高圈,投影后两条割线上没有变形,中央经 ...

  3. ArcGIS Engine10.2如何安装在 VisualStudio2013 开发环境下

    所谓工欲善其事必先利其器,10.2中的ArcObject SDK for Microsoft .Net Framework只能支持VS2010和VS2012环境. 那么如何在VS2013下安装呢? 准 ...

  4. berkeley db replica机制 - 消息处理

    repmgr_method.c, __repmgr_start_int()repmgr_method.c, __repmgr_start_msg_threads()repmgr_msg.c, __re ...

  5. PROC SORT

    PROC SORT DATA=输入数据集 <OUT=输出数据集><选项>; BY 关键变量; RUN; PROC SORT 语法如上,其中在尖括号中的可以不出现,也不会报错. ...

  6. Freemarker日期格式化处理

    基本参数: date: 只显示日期,不显示时间.如${createTime?date} 或${createTime?date('yyyy-MM-dd')} time: 只显示时间,不显示日期如${cr ...

  7. Linux Ubuntu12.04下安装OpenCv2.4.10

    参考 http://blog.sina.com.cn/s/blog_53b0956801010lfu.html 捣鼓了一个晚上了,OpenCv还没装好,本来以为看个类似的比如Ubuntu安装OpenC ...

  8. 用sql取出来的list需要处理成map的两种情况

    1. 原生sql: select a.id,a.name from a SQLQuery sqlQuery=this.getSession().createSQLQuery(sb.toString() ...

  9. onBlur事件与onfocus事件(js)

      onFocus事件就是当光标落在文本框中时发生的事件. onBlur事件是光标失去焦点时发生的事件. 可以编如下例子 1.html <HTML><HEAD><TITL ...

  10. 如何让MVC6在IIS上面跑

    asp.net5的MVC6发布出来的结果和MVC5之前版本的相差太远了,直接在本地的IIS服务器上面是不可能运行的. 看了汤姆大叔的MVC6项目发布与部署,讲了很多丰富的知识点.但是对于立即要解决问题 ...