private void CallCallbackPossiblyUnderLock(SendOrPostCallback callback, Object state)
        {
            ThreadContext threadContext = null;

            try {
                threadContext = _application.OnThreadEnter();
                try {
                    callback(state);
                }
                catch (Exception e) {
                    _error = ExceptionDispatchInfo.Capture(e);
                }
            }
            finally {
                if (threadContext != null)
                {
                    threadContext.DisassociateFromCurrentThread();
                }
            }
        }
 ISyncContextLock ISyncContext.Enter() {
     // Restores impersonation, Culture, etc.
     ThreadContext threadContext = new ThreadContext(_httpContext);
     threadContext.AssociateWithCurrentThread(_httpContext.UsesImpersonation);
     return threadContext;
 }
        // Initializes the thread on entry to the managed pipeline. A ThreadContext is returned, on
        // which the caller must call Leave.  The IIS7 integrated pipeline uses setImpersonationContext
        // to prevent it from being set until after the authentication notification.

        // OnThreadEnterPrivate returns ThreadContext.
        // ThreadContext.Enter sets variables that are stored on the thread,
        // and saves anything currently on the thread so it can be restored
        // during the call to ThreadContext.Leave.  All variables that are
        // modified on the thread should be stored in ThreadContext so they
        // can be restored later.  ThreadContext.Enter should only be called
        // when holding a lock on the HttpApplication instance.
        // ThreadContext.Leave is also normally called under the lock, but
        // the Integrated Pipeline may delay this call until after the call to
        // IndicateCompletion returns.  When IndicateCompletion is called,
        // IIS7 will execute the remaining notifications for the request on
        // the current thread.  As a performance improvement, we do not call
        // Leave before calling IndicateCompletion, and we do not call Enter/Leave
        // for the notifications executed while we are in the call to
        // IndicateCompletion.  But when IndicateCompletion returns, we do not
        // have a lock on the HttpApplication instance and therefore cannot
        // modify request state, such as the HttpContext or HttpApplication.
        // The only thing we can do is restore the state of the thread.
        // There's one problem, the Culture/UICulture may be changed by
        // user code that directly updates the values on the current thread, so
        // before leaving the pipeline we call ThreadContext.Synchronize to
        // synchronize the values that are stored on the HttpContext with what
        // is on the thread.  Because of this, the next notification will end up using
        // the Culture/UICulture set by user-code, just as it did on IIS6.
        private ThreadContext OnThreadEnterPrivate(bool setImpersonationContext) {
            ThreadContext threadContext = new ThreadContext(_context);
            threadContext.AssociateWithCurrentThread(setImpersonationContext);

            // An entry is added to the request timeout manager once per request
            // and removed in ReleaseAppInstance.
            if (!_timeoutManagerInitialized) {
                // ensure Timeout is set (see ASURT 148698)
                // to avoid ---- getting config later (ASURT 127388)
                _context.EnsureTimeout();

                HttpRuntime.RequestTimeoutManager.Add(_context);
                _timeoutManagerInitialized = true;
            }

            return threadContext;
        }
Example #4
0
        // Associates this ThreadContext with the current thread. This restores certain
        // ambient values associated with the current HttpContext, such as the current
        // user and cultures. It also sets HttpContext.Current.
        internal void AssociateWithCurrentThread(bool setImpersonationContext)
        {
            Debug.Assert(HttpContext != null); // only to be used when context is available
            Debug.Assert(Current != this, "This ThreadContext is already associated with this thread.");
            Debug.Assert(!HasBeenDisassociatedFromThread, "This ThreadContext has already been disassociated from a thread.");

            Debug.Trace("OnThread", GetTraceMessage("Enter1"));

            /*
             * !! IMPORTANT !!
             * Keep this logic in [....] with DisassociateFromCurrentThread and EnterExecutionContext.
             */

            // attach http context to the call context
            _originalHttpContext = DisposableHttpContextWrapper.SwitchContext(HttpContext);

            // set impersonation on the current thread
            if (setImpersonationContext)
            {
                SetImpersonationContext();
            }

            // set synchronization context for the current thread to support the async pattern
            _originalSynchronizationContext = AsyncOperationManager.SynchronizationContext;
            AspNetSynchronizationContextBase aspNetSynchronizationContext = HttpContext.SyncContext;

            AsyncOperationManager.SynchronizationContext = aspNetSynchronizationContext;

            // set ETW trace ID
            Guid g = HttpContext.WorkerRequest.RequestTraceIdentifier;

            if (g != Guid.Empty)
            {
                CallContext.LogicalSetData("E2ETrace.ActivityID", g);
            }

            // set SqlDependecyCookie
            HttpContext.ResetSqlDependencyCookie();

            // set principal on the current thread
            _originalThreadPrincipal = Thread.CurrentPrincipal;
            HttpApplication.SetCurrentPrincipalWithAssert(HttpContext.User);

            // only set culture on the current thread if it is not initialized
            SetRequestLevelCulture();

            // DevDivBugs 75042
            // set current thread in context if there is not there
            // the timeout manager  uses this to abort the correct thread
            if (HttpContext.CurrentThread == null)
            {
                _setCurrentThreadOnHttpContext = true;
                HttpContext.CurrentThread      = Thread.CurrentThread;
            }

            // Store a reference to the original ThreadContext.Current. It is possible that a parent
            // ThreadContext might already be associated with the current thread, e.g. if the current
            // stack contains a call to MgdIndicateCompletion (via
            // PipelineRuntime.ProcessRequestNotificationHelper). If this is the case, the child
            // ThreadContext will temporarily take over.
            _originalThreadContextCurrent = Current;
            Current = this;

            Debug.Trace("OnThread", GetTraceMessage("Enter2"));
        }
            internal override void ResumeSteps(Exception error)
            {
                bool          completed = false;
                bool          completedSynchronously = true;
                var           application            = _application;
                var           context     = application.Context;
                ThreadContext context2    = null;
                var           syncContext = context.SyncContext;

                lock (_application)
                {
                    try { context2 = application.OnThreadEnter(); }
                    catch (Exception exception) { if (error == null)
                                                  {
                                                      error = exception;
                                                  }
                    }
                    //
                    try
                    {
Label:
                        if (syncContext.Error != null)
                        {
                            error = syncContext.Error;
                            syncContext.ClearError();
                        }
                        if (error != null)
                        {
                            application.RecordError(error);
                            error = null;
                        }
                        if (syncContext.PendingOperationsCount > 0)
                        {
                            syncContext.SetLastCompletionWorkItem(this._resumeStepsWaitCallback);
                        }
                        else
                        {
                            if ((_currentStepIndex < _endRequestStepIndex) && ((context.Error != null) || _requestCompleted))
                            {
                                _currentStepIndex = _endRequestStepIndex;
                            }
                            else
                            {
                                _currentStepIndex++;
                            }
                            if (_currentStepIndex >= _execSteps.Length)
                            {
                                completed = true;
                            }
                            else
                            {
                                _numStepCalls++;
                                context.SyncContext.Enable();
                                error = application.ExecuteStep(_execSteps[_currentStepIndex], ref completedSynchronously);
                                completedSynchronously = true;
                                if (completedSynchronously)
                                {
                                    _numSyncStepCalls++;
                                    goto Label;
                                }
                            }
                        }
                    }
                    finally
                    {
                        if (context2 != null)
                        {
                            try { context2.Leave(); }
                            catch { }
                        }
                    }
                }
                if (completed)
                {
                    application.AsyncResult.Complete(_numStepCalls == _numSyncStepCalls, null, null);
                    application.ReleaseAppInstance();
                }
            }
        // Associates this ThreadContext with the current thread. This restores certain
        // ambient values associated with the current HttpContext, such as the current
        // user and cultures. It also sets HttpContext.Current.
        internal void AssociateWithCurrentThread(bool setImpersonationContext) {
            Debug.Assert(HttpContext != null); // only to be used when context is available
            Debug.Assert(Current != this, "This ThreadContext is already associated with this thread.");
            Debug.Assert(!HasBeenDisassociatedFromThread, "This ThreadContext has already been disassociated from a thread.");

            Debug.Trace("OnThread", GetTraceMessage("Enter1"));

            /*
             * !! IMPORTANT !!
             * Keep this logic in [....] with DisassociateFromCurrentThread and EnterExecutionContext.
             */

            // attach http context to the call context
            _originalHttpContext = DisposableHttpContextWrapper.SwitchContext(HttpContext);

            // set impersonation on the current thread
            if (setImpersonationContext) {
                SetImpersonationContext();
            }

            // set synchronization context for the current thread to support the async pattern
            _originalSynchronizationContext = AsyncOperationManager.SynchronizationContext;
            AspNetSynchronizationContextBase aspNetSynchronizationContext = HttpContext.SyncContext;
            AsyncOperationManager.SynchronizationContext = aspNetSynchronizationContext;

            // set ETW trace ID
            Guid g = HttpContext.WorkerRequest.RequestTraceIdentifier;
            if (g != Guid.Empty) {
                CallContext.LogicalSetData("E2ETrace.ActivityID", g);
            }

            // set SqlDependecyCookie
            HttpContext.ResetSqlDependencyCookie();

            // set principal on the current thread
            _originalThreadPrincipal = Thread.CurrentPrincipal;
            HttpApplication.SetCurrentPrincipalWithAssert(HttpContext.User);

            // only set culture on the current thread if it is not initialized
            SetRequestLevelCulture();

            // DevDivBugs 75042
            // set current thread in context if there is not there
            // the timeout manager  uses this to abort the correct thread
            if (HttpContext.CurrentThread == null) {
                _setCurrentThreadOnHttpContext = true;
                HttpContext.CurrentThread = Thread.CurrentThread;
            }

            // Store a reference to the original ThreadContext.Current. It is possible that a parent
            // ThreadContext might already be associated with the current thread, e.g. if the current
            // stack contains a call to MgdIndicateCompletion (via
            // PipelineRuntime.ProcessRequestNotificationHelper). If this is the case, the child
            // ThreadContext will temporarily take over.
            _originalThreadContextCurrent = Current;
            Current = this;

            Debug.Trace("OnThread", GetTraceMessage("Enter2"));
        }
 private ThreadContext OnThreadEnterPrivate(bool setImpersonationContext)
 {
     ThreadContext context = new ThreadContext(this._context);
     context.Enter(setImpersonationContext);
     if (!this._timeoutManagerInitialized)
     {
         this._context.EnsureTimeout();
         HttpRuntime.RequestTimeoutManager.Add(this._context);
         this._timeoutManagerInitialized = true;
     }
     return context;
 }