慎用System.Web.HttpContext.Current


每当控制流离开页面派生的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");
   }
}
GarsonZhang www.yesdotnet.com

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");
}
GarsonZhang www.yesdotnet.com

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

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

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

       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(15000);
        context.Response.Write("Request.Url = " + context.Request.Url);
    }
}
GarsonZhang www.yesdotnet.com

然而,在我的环境中,上面的代码会抛出一个异常,此异常来源于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(500);
         context.Response.Write("Do work");
      }
      finally
      {
         _resetEvent.Set();
      }
   }

AutoResetEvent _resetEvent = null;
}
GarsonZhang www.yesdotnet.com

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

 

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

 

 

来自 <https://www.cnblogs.com/david1989/p/3879201.html>

 

 

不错,最近我正好也思考过类似这方面的问题,尤其在异步模式下,HttpContext.Current调用方式不当很容易引发空引用异常。我的观点是不要轻易在任何地方(类库)使用HttpContext.Current,因为它并非无处不在,尽量把HttpContext的当前请求对象通过变量先保留起来,然后再传参或者供外部类库回调时重新获取请求上下文使用,见这一篇

 

来自 <https://www.cnblogs.com/david1989/p/3879201.html>

版权声明:本文为YES开发框架网发布内容,转载请附上原文出处连接
YES开发框架
上一篇:HttpContext.Current:异步模式下的疑似陷阱之源
下一篇:JS魔法堂:函数节流(throttle)与函数去抖(debounce)
评论列表

发表评论

评论内容
昵称:
关联文章

System.Web.HttpContext.Current
HttpContext.Current:异步模式下的疑似陷阱之源
AS.NET Core自定义类中全局访问HttpContext
Winform开启一个http服务,web服务
.Net Core——SignalR撸个游戏
网站分享
记一次 .NET 某市附属医院 Web程序 偶发性CPU爆高分析
windows平台的分布式微服务解决方案(5)--Web服务/WebApi的负载均衡
Web service 超过了最大请求长度
.NET中大型项目开发必备(5)--Web服务/WebApi的负载均衡
C# .net WEB判断当前环境是否是调试
网站迁移纪实:从Web Form 到 Asp.Net Core (Abp vNext 自定义开发)
.NETCoreProcess.Start打开网址出现异常
YES-WEB快速开发框架,.NET WEB开发平台,高效的web项目开发框架
sql server系统表详细说明 之 sys.system_views
sql server系统表详细说明 之 sys.system_parameters
sql server系统表详细说明 之 sys.system_objects
sql server系统表详细说明 之 sys.system_columns
使用Vue3轻松集成Lottie-web动画:从入门到实践
在Winform项目和Web API的.NetCore项目中使用Serilog 来记录日志信息

联系我们
联系电话:15090125178(微信同号)
电子邮箱:garson_zhang@163.com
站长微信二维码
微信二维码