每当控制流离开页面派生的Web表单上的代码的时候,HttpContext类的静态属性Current可能是有用的。 使用这个属性,我们可以获取当前请求(Request),响应(Response),会话(Session,)和应用程序对象(Application objects)以及请求更多服务。 以下面的代码为例。

private void Page_Load(object sender, System.EventArgs e)
{
MyClass myClass = new MyClass();
myClass.DoFoo();
} class MyClass
{
public void DoFoo()
{
HttpContext.Current.Response.Write("Doing Foo");
}
}

  Context在同一个应用程序域中请求当前上下文的能力是强大的,但也可能被滥用。你可以从业务对象使用HttpContext.Current打破你的架构层的界限,并且很轻松地将类与ASP.NET结合,而Windows Forms和the Compact Framework PDA则无法应用于此场景。

  HttpContext.Current是如何找到上下文当前请求。 此外,它总是能找到当前请求? 例如,下面的代码的行为会是什么?

private void Page_Load(object sender, System.EventArgs e)
{
ThreadPool.QueueUserWorkItem(new WaitCallback(DoWork));
} public void DoWork(object state)
{
HttpContext context = HttpContext.Current;
context.Response.Write("Do Work");
}

  答:上面的代码会生成一个System.NullReferenceException,因为HttpContext.Current返回null。从设计的角度来看,上面的代码至少存在两个问题,但是让我们讨论HttpContext.Current工作之前是如何工作的。

  快速查看反编译器实现Current的属性看起来像下面这样。

public static HttpContext get_Current()
{
return (CallContext.GetData("HtCt") as HttpContext);
}

CallContext是类似于方法调用的线程本地存储区的专用集合对象,并提供对每个逻辑执行线程都唯一的数据槽。CallContext 为调用路径提供数据槽。CallContext.SetData 和 CallContext.GetData 可用于管理应用程序代码中的调用上下文槽。每一调用路径都有唯一的数据槽;也就是说,调用路径之间不共享状态。这些数据槽是命名过的,名称用于访问数据槽,使用该名称可以显式地释放数据槽。线程本地存储是一个概念,其中在一个应用程序域中的每个逻辑线程都有一个唯一的数据槽,以保持特定于自身的数据。 线程不共享数据,一个线程不能修改本地数据到另一个线程中。ASP.NET中,选择一个线程来执行传入的请求后,在本地的线程存储参考当前请求的上下文。现在,无论线程在哪执行(一个业务对象,数据访问对象),上下文时时存在方便检索。

  知道了上面我们可以声明如下:如果在处理请求时,执行移动到不同的线程(通过QueueUserWorkItem,或异步委托,作为两个例子),当前背景下HttpContext.Current将不知道如何检索,将返回null。 你可能会认为解决这个问题的一种方法是将引用传递给工作线程,就像下面的例子。

private void Page_Load(object sender, System.EventArgs e)
{
WorkerClass2 worker = new WorkerClass2();
ThreadPool.QueueUserWorkItem(new WaitCallback(worker.DoWork), HttpContext.Current);
}
///………
class WorkerClass2
{
public void DoWork(object state)
{
HttpContext context = state as HttpContext;
Thread.Sleep();
context.Response.Write("Request.Url = " + context.Request.Url);
}
}

  

  然而,在我的环境中,上面的代码会抛出一个异常,此异常来源于mscoree.dll类库。上面的代码与QueueUserWorkItem例子的缺陷:两者都存在页面请求的生命周期,同时分配HttpContext对象有效生命周期。实际的开发中我们可以保持一个HttpContext参考副本,以防止垃圾回收器将HttpContext回收,ASP.NET运行时是自由的,当页面完成请求,将会自动清除一些垃圾资源。我不知道上面的代码会发生什么,在不同的情况下,代码可以在一些机器上运行,但失败的几率确实存在,并应避免这些导致失败的条件。

  有一些方法可以保证页面请求没有完成,直到工作线程完成其工作,例如,下面的代码。

private void Page_Load(object sender, System.EventArgs e)
{
WorkerClass worker = new WorkerClass(_resetEvent);
ThreadPool.QueueUserWorkItem(new WaitCallback(worker.DoWork),
HttpContext.Current);
try
{
_resetEvent.WaitOne();
}
finally
{
_resetEvent.Close();
}
}
AutoResetEvent _resetEvent = new AutoResetEvent(false);

class WorkerClass
{
public WorkerClass(AutoResetEvent resetEvent)
{
_resetEvent = resetEvent;
} public void DoWork(object state)
{
try
{
HttpContext context = state as HttpContext;
Thread.Sleep();
context.Response.Write("Do work");
}
finally
{
_resetEvent.Set();
}
} AutoResetEvent _resetEvent = null;
}

  

  上面的代码能正常的工作在浏览器中。 然而,设计仍然存在一些疑虑。 首先,ASP.NET运行时处理多个请求的时候,它的线程使用数量有限。 我们刚刚完成相同数量的工作,但我​​们已经增加了一倍所需的线程数,产生额外的上下文切换,和现在有一个同步原语来管理。 当等待工作任务完成,在原始线程执行额外的工作,则可能是一个好处。 然而,一般来说,你更应该使用额外的线程在ASP.NET中使用一定量的保留的做法。

  在这篇文章中,我们已经深入了解HttpContext.Current是如何工作的,并看到了一些场景,我们需要谨慎行事。 不要滥用HttpContext.Current,每当调用在代码调用它的时候,应多检查您的设计架构。

慎用System.Web.HttpContext.Current的更多相关文章

  1. System.Web.HttpContext.Current.Session为NULL解决方法

    http://www.cnblogs.com/tianguook/archive/2010/09/27/1836988.html 自定义 HTTP 处理程序,从IHttpHandler继承,在写Sys ...

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

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

  3. HttpContext为null new HttpContextWrapper(System.Web.HttpContext.Current)

    HttpContext = (context == null ? new HttpContextWrapper(System.Web.HttpContext.Current) : context);

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

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

  5. System.Web.HttpContext.Current.Session获取值出错

    在自定义类库CS文件里使用System.Web.HttpContext.Current.Session获取Session时提示错误:未将对象引用设置到对象的实例. 一般情况下通过这种方式获取Sessi ...

  6. System.Web.HttpContext.Current.Session为NULL值的问题?

    自定义 HTTP 处理程序,从IHttpHandler继承,在写System.Web.HttpContext.Current.Session["Value"]的时 候,没有问题,但 ...

  7. .NET System.Web.HttpContext.Current.Request报索引超出数组界限。

    移动端使用Dio发送 FormData, 请求类型 multipart/form-data, FormData内可以一个或多个包含文件时. 请求接口时获取上传的fomdata数据使用 System.W ...

  8. System.Web.HttpContext.Current.Request用法

    public static void SetRegisterSource() { if (System.Web.HttpContext.Current.Request["website&qu ...

  9. System.Web.HttpContext.Current 跟踪分析

    public static HttpContext Current { get { return ContextBase.Current as HttpContext; } set { Context ...

随机推荐

  1. Docker 私有仓库最简便的搭建方法

    http://blog.csdn.net/wangtaoking1/article/details/44180901/ Docker学习笔记 — Docker私有仓库搭建http://www.jian ...

  2. 在 Linux 客户端配置基于 Kerberos 身份验证的 NFS 服务器

    在这篇文章中我们会介绍配置基于 Kerberos 身份验证的 NFS 共享的整个流程.假设你已经配置好了一个 NFS 服务器和一个客户端.如果还没有,可以参考 安装和配置 NFS 服务器[2] - 它 ...

  3. 491. Palindrome Number【easy】

    Check a positive number is a palindrome or not. A palindrome number is that if you reverse the whole ...

  4. layui当点击增加的时候,将form中的值获取的添加到table行中代码

    layui.use(['table','layer'],function(){ var $=layui.$, table=layui.table, layer=layui.layer; functio ...

  5. django中使用POST方法 使用ajax后出现“CSRF token missing or incorrect”

    这个是因为在django的ajax中默认添加了token,因此需要在cookie中增加token头信息. 首先使用JavaScript函数获取token: function getCookie(nam ...

  6. JavaScript变量的生命周期

    最近看国外经典教材的时候发现JavaScript与熟知的Java,C,C++都不同的特性,其中一个就是变量的生命周期.   1.在JavaScript中,对于for循环中定义的i变量,其生命周期在循环 ...

  7. session用户账号认证(一个用户登陆,踢出前一个用户)

    在web.xml中配置: <listener> <listener-class>cn.edu.hbcf.common.listener.SessionAttributeList ...

  8. TCP/IP详解读书笔记:概述

    分层 分层是一种很通用的架构模式.通过分层,可以把一个系统分解成多个层,每个层专注于各自的功能,并提供接口给上面的层调用.上面的层不需要了解调用层的详细实现,只依赖于其接口,这就给维护带来了很大的好处 ...

  9. android最佳实践的建议(翻译自android-best-practices)

    Best practices in Android development Use Gradle and its recommended project structure 使用Gradle和其推荐的 ...

  10. C0302 将一个代码块中的内容保存在文件中, 查看一个rpm包是否可以安装

    #!/bin/bash # 这个脚本是用来描述和确认是否可以安装一个rpm包 # 在一个文件中保存输出 SUCCESS=0 E_NOARGS=65 if [ -z "$1" ] t ...