public override object SetHostExecutionContext(HostExecutionContext hostExecutionContext) { AspNetHostExecutionContext castHostExecutionContext = hostExecutionContext as AspNetHostExecutionContext; if (castHostExecutionContext != null) { // Call base.SetHostExecutionContext before calling our own logic. object baseRevertParameter = null; if (castHostExecutionContext.BaseContext != null) { baseRevertParameter = base.SetHostExecutionContext(castHostExecutionContext.BaseContext); } ThreadContext currentContext = ThreadContext.Current; if (currentContext != null && currentContext.HttpContext.ThreadContextId == castHostExecutionContext.HttpContextThreadContextId) { // If we reached this point, then 'castHostExecutionContext' was captured for the HttpContext // that is associated with the ThreadContext that is assigned to the current thread. We can // safely restore it. Action threadContextCleanupAction = currentContext.EnterExecutionContext(); // Perform cleanup in the opposite order from initialization. return((RevertAction)(() => { threadContextCleanupAction(); if (baseRevertParameter != null) { base.Revert(baseRevertParameter); } })); } else { // If we reached this point, then 'castHostExecutionContext' was captured by us // but is not applicable to the current thread. This can happen if the developer // called ThreadPool.QueueUserWorkItem, for example. We don't restore HttpContext // on such threads since they're not under the control of ASP.NET. In this case, // we have already called base.SetHostExecutionContext, so we just need to return // the result of that function directly to our caller. return(baseRevertParameter); } } else { // If we reached this point, then 'hostExecutionContext' was generated by our // base class instead of by us, so just delegate to the base implementation. return(base.SetHostExecutionContext(hostExecutionContext)); } }