HttpContext.Current is null in an asynchronous Callback

后端 未结 3 1608
心在旅途
心在旅途 2020-12-14 18:00

Trying to access the HttpContext.Current in a method call back so can I modify a Session variable, however I receive the exception that HttpC

相关标签:
3条回答
  • 2020-12-14 18:33

    Here's a class-based solution that is working for simple cases so far in MVC5 (MVC6 supports a DI-based context).

    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;
            }
        }
    }
    

    To use it can hook in from Global.asax.cs:

        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();
        }
    

    Then can use this in place of HttpContext.Current:

        HttpContextProvider.Current
    

    There may be issues as I currently do not understand this related answer. Please comment.

    Reference: AsyncLocal (requires .NET 4.6)

    0 讨论(0)
  • 2020-12-14 18:37

    Please see the following article for an explanation on why the Session variable is null, and possible work arounds

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

    quoted from the from the article;

    the current HttpContext is actually in thread-local storage, which explains why child threads don’t have access to it

    And as a proposed work around the author says

    pass a reference to it in your child thread. Include a reference to HttpContext in the “state” object of your callback method, and then you can store it to HttpContext.Current on that thread

    0 讨论(0)
  • 2020-12-14 18:44

    When using threads or an async function, HttpContext.Current is not available.

    Try using:

    HttpContext current;
    if(HttpContext != null && HttpContext.Current != null)
    {
      current = HttpContext.Current;
    }
    else
    {
        current = this.CurrentContext; 
        //**OR** current = threadInstance.CurrentContext; 
    }
    

    Once you set current with a proper instance, the rest of your code is independent, whether called from a thread or directly from a WebRequest.

    0 讨论(0)
提交回复
热议问题