首页
学习
活动
专区
工具
TVP
发布
社区首页 >问答首页 >异步回调中的HttpContext.Current为空

异步回调中的HttpContext.Current为空
EN

Stack Overflow用户
提问于 2014-07-03 11:02:17
回答 3查看 30K关注 0票数 21

尝试在方法回调中访问HttpContext.Current以便可以修改Session变量,但是我收到HttpContext.Currentnull的异常。当_anAgent对象触发回调方法时,它将被异步激发。

在SO上查看 之后,我仍然不确定这个问题的解决方案。

我的代码的简化版本如下所示:

代码语言:javascript
复制
public partial class Index : System.Web.UI.Page

  protected void Page_Load()
  {
    // aCallback is an Action<string>, triggered when a callback is received
    _anAgent = new WorkAgent(...,
                             aCallback: Callback);
    ...
    HttpContext.Current.Session["str_var"] = _someStrVariable;
  }

  protected void SendData() // Called on button click
  {
    ...
    var some_str_variable = HttpContext.Current.Session["str_var"];

    // The agent sends a message to another server and waits for a call back
    // which triggers a method, asynchronously.
    _anAgent.DispatchMessage(some_str_variable, some_string_event)
  }

  // This method is triggered by the _webAgent
  protected void Callback(string aStr)
  {
    // ** This culprit throws the null exception **
    HttpContext.Current.Session["str_var"] = aStr;
  }

  [WebMethod(EnableSession = true)]
  public static string GetSessionVar()
  {
    return HttpContext.Current.Session["str_var"]
  }
}

不确定是否有必要,但我的WorkAgent类如下所示:

代码语言:javascript
复制
public class WorkAgent
{
  public Action<string> OnCallbackReceived { get; private set; }

  public WorkAgent(...,
                   Action<string> aCallback = null)
  {
    ...
    OnCallbackReceived = aCallback;
  }

  ...

  // This method is triggered when a response is received from another server
  public BackendReceived(...)
  {
    ...
    OnCallbackReceived(some_string);
  }
}

代码中发生的事情:

单击按钮将调用SendData()方法,在该方法中,_webAgent将向另一个服务器发送一条消息并等待回复(同时,用户仍然可以与此页面交互并引用相同的SessionID)。一旦收到,它将调用BackendReceived()方法,在.aspx.cs页面中,该方法将调用Callback()方法。

问题:

WorkAgent触发Callback()方法时,它会尝试访问HttpContext.Current,即null。为什么在忽略异常的情况下继续操作,仍然可以使用ajax返回的GetSessionVar()方法获得相同的SessionIDSession变量。

我是否应该启用aspNetCompatibilityEnabled设置?

我是否应该创建某种类型的asynchronous module handler

这与Integrated/Classic mode有关吗

EN

回答 3

Stack Overflow用户

发布于 2016-07-13 05:19:01

这是一个基于类的解决方案,到目前为止,它在MVC5 (MVC6支持基于DI的上下文)中适用于简单的情况。

代码语言:javascript
复制
using System.Threading;
using System.Web;

namespace SomeNamespace.Server.ServerCommon.Utility
{
    /// <summary>
    /// Preserve HttpContext.Current across async/await calls.  
    /// Usage: Set it at beginning of request and clear at end of request.
    /// </summary>
    static public class HttpContextProvider
    {
        /// <summary>
        /// Property to help ensure a non-null HttpContext.Current.
        /// Accessing the property will also set the original HttpContext.Current if it was null.
        /// </summary>
        static public HttpContext Current => HttpContext.Current ?? (HttpContext.Current = __httpContextAsyncLocal?.Value);

        /// <summary>
        /// MVC5 does not preserve HttpContext across async/await calls.  This can be used as a fallback when it is null.
        /// It is initialzed/cleared within BeginRequest()/EndRequest()
        /// MVC6 may have resolved this issue since constructor DI can pass in an HttpContextAccessor.
        /// </summary>
        static private AsyncLocal<HttpContext> __httpContextAsyncLocal = new AsyncLocal<HttpContext>();

        /// <summary>
        /// Make the current HttpContext.Current available across async/await boundaries.
        /// </summary>
        static public void OnBeginRequest()
        {
            __httpContextAsyncLocal.Value = HttpContext.Current;
        }

        /// <summary>
        /// Stops referencing the current httpcontext
        /// </summary>
        static public void OnEndRequest()
        {
            __httpContextAsyncLocal.Value = null;
        }
    }
}

要使用它,可以从Global.asax.cs连接:

代码语言:javascript
复制
    public MvcApplication() // constructor
    {            
        PreRequestHandlerExecute += new EventHandler(OnPreRequestHandlerExecute);
        EndRequest += new EventHandler(OnEndRequest);
    } 

    protected void OnPreRequestHandlerExecute(object sender, EventArgs e)
    {
        HttpContextProvider.OnBeginRequest();   // preserves HttpContext.Current for use across async/await boundaries.            
    }

    protected void OnEndRequest(object sender, EventArgs e)
    {
        HttpContextProvider.OnEndRequest();
    }

然后可以使用它来代替HttpContext.Current:

代码语言:javascript
复制
    HttpContextProvider.Current

可能会有问题,因为我目前不理解这个related answer。请发表意见。

参考:AsyncLocal (需要.NET 4.6)

票数 11
EN

Stack Overflow用户

发布于 2014-07-03 13:13:06

有关会话变量为null的原因以及可能的解决方法,请参阅以下文章

http://adventuresdotnet.blogspot.com/2010/10/httpcontextcurrent-and-threads-with.html

引用自文章中的;

当前的HttpContext实际上在线程本地存储中,这解释了为什么子线程无法访问它

正如作者提出的那样,作者说

在你的子线程中传递一个对它的引用。在回调方法的“HttpContext”对象中包含对状态的引用,然后可以将其存储到线程

上的HttpContext.Current

票数 4
EN

Stack Overflow用户

发布于 2014-07-03 13:20:58

使用线程或async函数时,HttpContext.Current不可用。

尝试使用:

代码语言:javascript
复制
HttpContext current;
if(HttpContext != null && HttpContext.Current != null)
{
  current = HttpContext.Current;
}
else
{
    current = this.CurrentContext; 
    //**OR** current = threadInstance.CurrentContext; 
}

一旦使用适当的实例设置了current,剩下的代码就是独立的,无论是从线程调用还是直接从WebRequest调用。

票数 4
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/24544272

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档