今天在对项目代码进行异步化改进的时候,遇到一个奇怪的问题(莫笑,以前没遇过),正如标题一样,HttpContext.Current 在 await 异步执行之后,就会变为 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 这个东西,我们并不陌生,在进行 ASP.NET 应用程序开发的时候,我们经常会用到,比如获取当前请求的一些值,首先它是一个线程静态属性(thread-static variable),注意其中的关键字:当前请求和线程,也就是说它是和请求线程相关的,在 ASP.NET 应用程序中,一个请求线程会贯穿整个请求过程,所以我们可以在这个请求的任何地方,都可以访问到 HttpContext.Current,这也就是它的“强大之处”,但是如果涉及到异步多线程呢?就不是这么回事了,因为 HttpContext.Current 依附的是当前请求的主线程,当我们使用 await 异步执行一些代码的时候,再次执行下面的代码,其实就不是当前请求线程了,所以我们再次访问 HttpContext.Current 的时候,就变为 null 了,这个问题告诫我们,ASP.NET 应用程序中,如果进行异步化,使用 HttpContext.Current 一定要小心谨慎。

  • 需要注意的是:HttpContext.Current 在没有进行 await 操作的时候,都是可以获取到值的。

如果我们的 ASP.NET 应用程序进行了异步化,然后还必须用到 HttpContext.Current,那我们该怎么解决这个问题?

解决的方式有很多,如果应用程序很简单,我们可以在 await 操作之前,先用变量存储 HttpContext.Current,用到的地方直接用这个变量就行了,当然这不是一个“解决问题”的方法,还有一种是用 Cache,可以参考:system-web-httpcontext-current-nulls-itself-after-checking-for-a-cache,我觉得这种方式也是“瞎忽悠”,没有从根本问题上进行解决。

其实想想问题的根源,就是如何在多个线程中共享一个 HttpContext.Current,这个在 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.

那我们如何在 ASP.NET 应用程序中,进行运用呢?答案很简单,我们只需要在 web.config 中指定 targetFramework 版本为 4.5 即可:

<httpRuntime targetFramework="4.5" />

或者在 appSettings 中添加如下 key(测试可用):

<add key="aspnet:UseTaskFriendlySynchronizationContext" value="true" />

参考资料:

Why is HttpContext.Current null after await?的更多相关文章

  1. Why is HttpContext.Current null during the Session_End event?

    Why is HttpContext.Current null during the Session_End event? On Session_End there is no communicati ...

  2. ASP.NET多线程下使用HttpContext.Current为null解决方案 2015-01-22 15:23 349人阅读 评论(0) 收藏

    问题一:多线程下获取文件绝对路径 当我们使用HttpContext.Current.Server.MapPath(strPath)获取绝对路径时HttpContext.Current为null,解决办 ...

  3. ASP.NET多线程下使用HttpContext.Current为null解决方案 2015-01-22 15:23 350人阅读 评论(0) 收藏

    问题一:多线程下获取文件绝对路径 当我们使用HttpContext.Current.Server.MapPath(strPath)获取绝对路径时HttpContext.Current为null,解决办 ...

  4. 多线程中使用HttpContext.Current为null的解决办法

    HttpContext.Current.Server.MapPath(logFile)   这个是得到具体路径的方法  正常情况下是可以的 多线程情况下就为null 下边的代码原本的作用是把网站的异常 ...

  5. HttpContext.Current and Web Api

    Using HttpContext.Current in WebApi is dangerous because of async HttpContext.Current gets the curre ...

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

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

  7. 我所知道的HttpContext.Current

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

  8. System.Web.HttpContext.Current.Server.MapPath("~/upload/SH") 未将对象引用设置为实例对象

    做项目的时候,System.Web.HttpContext.Current.Server.MapPath("~/upload/SH")   获取路径本来这个方法用的好好的 因为需要 ...

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

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

随机推荐

  1. MFC覆盖OnPrepareDC实现“所见即所得”打印

    附件下载:http://files.cnblogs.com/mengdejun/print.zip void CPrintView::OnPrepareDC(CDC* pDC, CPrintInfo* ...

  2. python中的参数问题

    python中的有默认参数和可变参数之分 默认参数arg 可变参数args, kargs 默认参数arg就是调用指定参数 可变参数*arg调用时传入的的参数会被python自动包装为列表 可变参数ka ...

  3. slf4j的简单介绍

    SLF4J,Simple Logging Facade for JAVA,是一个十分简单的的日志facade,对于不同的日志框架做了一个封装. 对比common logging,Common logg ...

  4. android 之HttpURLConnection的post,get方式请求数据

    get方式和post方式的区别: 1.请求的URL地址不同: post:"http://xx:8081//servlet/LoginServlet" get:http://xxx: ...

  5. Apache服务器在80端口配置多域名虚拟主机的方法

    我们在配置一台服务器的时候,如果只运行一个站点,往往过于浪费资源.Nginx和Apache都可以通过配置虚拟主机实现多站点.配置虚拟主机的方式主要有两种,一种是多个不同端口对应的多个虚拟主机站点,一种 ...

  6. C/C++编译和链接过程详解 (重定向表,导出符号表,未解决符号表)

    详解link  有 些人写C/C++(以下假定为C++)程序,对unresolved external link或者duplicated external simbol的错误信息不知所措(因为这样的错 ...

  7. C#中ToString格式大全

    更多资源:http://denghejun.github.io C 货币 2.5.ToString("C") ¥2.50 D 十进制数 25.ToString("D5&q ...

  8. IDT HOOK思路整理

    IDT(中断描述符表)分为IRQ(真正的硬件中断)和软件中断(又叫异常). HOOK的思路为,替换键盘中断处理的函数地址为自己的函数地址.这样在键盘驱动和过滤驱动之前就可以截获键盘输入. 思路确定之后 ...

  9. ExtJS扩展:扩展grid

    ExtJs的grid功能很强大,但是有时候觉得总是少那么一点点功能,我们就来扩展它,让它用起来更方便. 今天我们要扩展的是:根据记录的选择数量来禁用或启用grid toolbar上的某些按钮. 本文所 ...

  10. DBImport v3.5 中文版发布:数据库定时同步及文档生成工具(IT人员必备)

    前言: 趁着最近的休息时间,只能多勤快些:多写代码,多更新文章. 因为一旦投入新的工作,估计博客又会恢复到一年才产几篇的状态. 对于DBImport,因为用户的意见,增加了一个亮点功能,让软件B格升为 ...