Code:
/ 4.0 / 4.0 / DEVDIV_TFS / Dev10 / Releases / RTMRel / ndp / fx / src / Net / System / Net / _ContextAwareResult.cs / 1305376 / _ContextAwareResult.cs
//------------------------------------------------------------------------------ //// Copyright (c) Microsoft Corporation. All rights reserved. // //----------------------------------------------------------------------------- namespace System.Net { using System.Threading; using System.Security; using System.Security.Principal; using System.Security.Permissions; // // This is used by ContextAwareResult to cache callback closures between similar calls. Create one of these and // pass it in to FinishPostingAsyncOp() to prevent the context from being captured in every iteration of a looped async call. // // I thought about making the delegate and state into weak references, but decided against it because: // - The delegate is very likely to be abandoned by the user right after calling BeginXxx, making caching it useless. There's // no easy way to weakly reference just the target. // - We want to support identifying state via object.Equals() (especially value types), which means we need to keep a // reference to the original. Plus, if we're holding the target, might as well hold the state too. // The user will need to disable caching if they want their target/state to be instantly collected. // // For now the state is not included as part of the closure. It is too common a pattern (for example with socket receive) // to have several pending IOs differentiated by their state object. We don't want that pattern to break the cache. // internal class CallbackClosure { private AsyncCallback savedCallback; private ExecutionContext savedContext; internal CallbackClosure(ExecutionContext context, AsyncCallback callback) { if (callback != null) { savedCallback = callback; savedContext = context; } } internal bool IsCompatible(AsyncCallback callback) { if (callback == null || savedCallback == null) return false; // Delegates handle this ok. AsyncCallback is sealed and immutable, so if this succeeds, we are safe to use // the passed-in instance. if (!object.Equals(savedCallback, callback)) return false; return true; } internal AsyncCallback AsyncCallback { get { return savedCallback; } } internal ExecutionContext Context { get { return savedContext; } } } // // This class will ensure that the correct context is restored on the thread before invoking // a user callback. // internal class ContextAwareResult : LazyAsyncResult { [Flags] private enum StateFlags { None = 0x00, CaptureIdentity = 0x01, CaptureContext = 0x02, ThreadSafeContextCopy = 0x04, PostBlockStarted = 0x08, PostBlockFinished = 0x10, } // This needs to be volatile so it's sure to make it over to the completion thread in time. private volatile ExecutionContext _Context; private object _Lock; private StateFlags _Flags; #if !FEATURE_PAL private WindowsIdentity _Wi; #endif internal ContextAwareResult(object myObject, object myState, AsyncCallback myCallBack) : this(false, false, myObject, myState, myCallBack) { } // Setting captureIdentity enables the Identity property. This will be available even if ContextCopy isn't, either because // flow is suppressed or it wasn't needed. (If ContextCopy isn't available, Identity may or may not be. But if it is, it // should be used instead of ContextCopy for impersonation - ContextCopy might not include the identity.) // // Setting forceCaptureContext enables the ContextCopy property even when a null callback is specified. (The context is // always captured if a callback is given.) internal ContextAwareResult(bool captureIdentity, bool forceCaptureContext, object myObject, object myState, AsyncCallback myCallBack) : this(captureIdentity, forceCaptureContext, false, myObject, myState, myCallBack) { } internal ContextAwareResult(bool captureIdentity, bool forceCaptureContext, bool threadSafeContextCopy, object myObject, object myState, AsyncCallback myCallBack) : base(myObject, myState, myCallBack) { if (forceCaptureContext) { _Flags = StateFlags.CaptureContext; } if (captureIdentity) { _Flags |= StateFlags.CaptureIdentity; } if (threadSafeContextCopy) { _Flags |= StateFlags.ThreadSafeContextCopy; } } #if !FEATURE_PAL // Security: We need an assert for a call into WindowsIdentity.GetCurrent [SecurityPermissionAttribute(SecurityAction.Assert, Flags=SecurityPermissionFlag.ControlPrincipal)] private void SafeCaptureIdenity() { _Wi = WindowsIdentity.GetCurrent(); } #endif // // This can be used to establish a context during an async op for something like calling a delegate or demanding a permission. // May block briefly if the context is still being produced. // // Returns null if called from the posting thread. // internal ExecutionContext ContextCopy { get { GlobalLog.Assert(!InternalPeekCompleted || (_Flags & StateFlags.ThreadSafeContextCopy) != 0, "ContextAwareResult#{0}::ContextCopy|Called on completed result.", ValidationHelper.HashString(this)); if (InternalPeekCompleted) { throw new InvalidOperationException(SR.GetString(SR.net_completed_result)); } ExecutionContext context = _Context; if (context != null) { return context.CreateCopy(); } // Make sure the context was requested. GlobalLog.Assert(AsyncCallback != null || (_Flags & StateFlags.CaptureContext) != 0, "ContextAwareResult#{0}::ContextCopy|No context captured - specify a callback or forceCaptureContext.", ValidationHelper.HashString(this)); // Just use the lock to block. We might be on the thread that owns the lock which is great, it means we // don't need a context anyway. if ((_Flags & StateFlags.PostBlockFinished) == 0) { GlobalLog.Assert(_Lock != null, "ContextAwareResult#{0}::ContextCopy|Must lock (StartPostingAsyncOp()) { ... FinishPostingAsyncOp(); } when calling ContextCopy (unless it's only called after FinishPostingAsyncOp).", ValidationHelper.HashString(this)); lock (_Lock) { } } GlobalLog.Assert(!InternalPeekCompleted || (_Flags & StateFlags.ThreadSafeContextCopy) != 0, "ContextAwareResult#{0}::ContextCopy|Result became completed during call.", ValidationHelper.HashString(this)); if (InternalPeekCompleted) { throw new InvalidOperationException(SR.GetString(SR.net_completed_result)); } context = _Context; return context == null ? null : context.CreateCopy(); } } #if !FEATURE_PAL // // Just like ContextCopy. // internal WindowsIdentity Identity { get { GlobalLog.Assert(!InternalPeekCompleted || (_Flags & StateFlags.ThreadSafeContextCopy) != 0, "ContextAwareResult#{0}::Identity|Called on completed result.", ValidationHelper.HashString(this)); if (InternalPeekCompleted) { throw new InvalidOperationException(SR.GetString(SR.net_completed_result)); } if (_Wi != null) { return _Wi; } // Make sure the identity was requested. GlobalLog.Assert((_Flags & StateFlags.CaptureIdentity) != 0, "ContextAwareResult#{0}::Identity|No identity captured - specify captureIdentity.", ValidationHelper.HashString(this)); // Just use the lock to block. We might be on the thread that owns the lock which is great, it means we // don't need an identity anyway. if ((_Flags & StateFlags.PostBlockFinished) == 0) { GlobalLog.Assert(_Lock != null, "ContextAwareResult#{0}::Identity|Must lock (StartPostingAsyncOp()) { ... FinishPostingAsyncOp(); } when calling Identity (unless it's only called after FinishPostingAsyncOp).", ValidationHelper.HashString(this)); lock (_Lock) { } } GlobalLog.Assert(!InternalPeekCompleted || (_Flags & StateFlags.ThreadSafeContextCopy) != 0, "ContextAwareResult#{0}::Identity|Result became completed during call.", ValidationHelper.HashString(this)); if (InternalPeekCompleted) { throw new InvalidOperationException(SR.GetString(SR.net_completed_result)); } return _Wi; } } #endif #if DEBUG // Want to be able to verify that the Identity was requested. If it was requested but isn't available // on the Identity property, it's either available via ContextCopy or wasn't needed (synchronous). internal bool IdentityRequested { get { return (_Flags & StateFlags.CaptureIdentity) != 0; } } #endif internal object StartPostingAsyncOp() { return StartPostingAsyncOp(true); } // // If ContextCopy or Identity will be used, the return value should be locked until FinishPostingAsyncOp() is called // or the operation has been aborted (e.g. by BeginXxx throwing). Otherwise, this can be called with false to prevent the lock // object from being created. // internal object StartPostingAsyncOp(bool lockCapture) { GlobalLog.Assert(!InternalPeekCompleted, "ContextAwareResult#{0}::StartPostingAsyncOp|Called on completed result.", ValidationHelper.HashString(this)); DebugProtectState(true); _Lock = lockCapture ? new object() : null; _Flags |= StateFlags.PostBlockStarted; return _Lock; } // // Call this when returning control to the user. // internal bool FinishPostingAsyncOp() { // Ignore this call if StartPostingAsyncOp() failed or wasn't called, or this has already been called. if ((_Flags & (StateFlags.PostBlockStarted | StateFlags.PostBlockFinished)) != StateFlags.PostBlockStarted) { return false; } _Flags |= StateFlags.PostBlockFinished; ExecutionContext cachedContext = null; return CaptureOrComplete(ref cachedContext, false); } // // Call this when returning control to the user. Allows a cached Callback Closure to be supplied and used // as appropriate, and replaced with a new one. // internal bool FinishPostingAsyncOp(ref CallbackClosure closure) { // Ignore this call if StartPostingAsyncOp() failed or wasn't called, or this has already been called. if ((_Flags & (StateFlags.PostBlockStarted | StateFlags.PostBlockFinished)) != StateFlags.PostBlockStarted) { return false; } _Flags |= StateFlags.PostBlockFinished; // Need a copy of this ref argument since it can be used in many of these calls simultaneously. CallbackClosure closureCopy = closure; ExecutionContext cachedContext; if (closureCopy == null) { cachedContext = null; } else { if (!closureCopy.IsCompatible(AsyncCallback)) { // Clear the cache as soon as a method is called with incompatible parameters. closure = null; cachedContext = null; } else { // If it succeeded, we want to replace our context/callback with the one from the closure. // Using the closure's instance of the callback is probably overkill, but safer. AsyncCallback = closureCopy.AsyncCallback; cachedContext = closureCopy.Context; } } bool calledCallback = CaptureOrComplete(ref cachedContext, true); // Set up new cached context if we didn't use the previous one. if (closure == null && AsyncCallback != null && cachedContext != null) { closure = new CallbackClosure(cachedContext, AsyncCallback); } return calledCallback; } /* enable when needed // // Use this to block until FinishPostingAsyncOp() completes. Must check for null. // internal object PostingLock { get { return _Lock; } } // // Call this if you want to cancel any flowing. // internal void InvokeCallbackWithoutContext(object result) { ProtectedInvokeCallback(result, (IntPtr) 1); } */ // protected override void Cleanup() { base.Cleanup(); GlobalLog.Print("ContextAwareResult#" + ValidationHelper.HashString(this) + "::Cleanup()"); #if !FEATURE_PAL if (_Wi != null) { _Wi.Dispose(); _Wi = null; } #endif } // // This must be called right before returning the result to the user. It might call the callback itself, // to avoid flowing context. Even if the operation completes before this call, the callback won't have been // called. // // Returns whether the operation completed [....] or not. // private bool CaptureOrComplete(ref ExecutionContext cachedContext, bool returnContext) { GlobalLog.Assert((_Flags & StateFlags.PostBlockStarted) != 0, "ContextAwareResult#{0}::CaptureOrComplete|Called without calling StartPostingAsyncOp.", ValidationHelper.HashString(this)); // See if we're going to need to capture the context. bool capturingContext = AsyncCallback != null || (_Flags & StateFlags.CaptureContext) != 0; #if !FEATURE_PAL // Peek if we've already completed, but don't fix CompletedSynchronously yet // Capture the identity if requested, unless we're going to capture the context anyway, unless // capturing the context won't be sufficient. if ((_Flags & StateFlags.CaptureIdentity) != 0 && !InternalPeekCompleted && (!capturingContext || SecurityContext.IsWindowsIdentityFlowSuppressed())) { GlobalLog.Print("ContextAwareResult#" + ValidationHelper.HashString(this) + "::CaptureOrComplete() starting identity capture"); SafeCaptureIdenity(); } #endif // No need to flow if there's no callback, unless it's been specifically requested. // Note that Capture() can return null, for example if SuppressFlow() is in effect. if (capturingContext && !InternalPeekCompleted) { GlobalLog.Print("ContextAwareResult#" + ValidationHelper.HashString(this) + "::CaptureOrComplete() starting capture"); if (cachedContext == null) { cachedContext = ExecutionContext.Capture(); } if (cachedContext != null) { if (!returnContext) { _Context = cachedContext; cachedContext = null; } else { _Context = cachedContext.CreateCopy(); } } GlobalLog.Print("ContextAwareResult#" + ValidationHelper.HashString(this) + "::CaptureOrComplete() _Context:" + ValidationHelper.HashString(_Context)); } else { // Otherwise we have to have completed synchronously, or not needed the context. GlobalLog.Print("ContextAwareResult#" + ValidationHelper.HashString(this) + "::CaptureOrComplete() skipping capture"); cachedContext = null; GlobalLog.Assert(AsyncCallback == null || CompletedSynchronously, "ContextAwareResult#{0}::CaptureOrComplete|Didn't capture context, but didn't complete synchronously!", ValidationHelper.HashString(this)); } // Now we want to see for sure what to do. We might have just captured the context for no reason. // This has to be the first time the state has been queried "for real" (apart from InvokeCallback) // to guarantee synchronization with Complete() (otherwise, Complete() could try to call the // callback without the context having been gotten). DebugProtectState(false); if (CompletedSynchronously) { GlobalLog.Print("ContextAwareResult#" + ValidationHelper.HashString(this) + "::CaptureOrComplete() completing synchronously"); base.Complete(IntPtr.Zero); return true; } return false; } // // Is guaranteed to be called only once. If called with a non-zero userToken, the context is not flowed. // protected override void Complete(IntPtr userToken) { GlobalLog.Print("ContextAwareResult#" + ValidationHelper.HashString(this) + "::Complete() _Context(set):" + (_Context != null).ToString() + " userToken:" + userToken.ToString()); // If no flowing, just complete regularly. if ((_Flags & StateFlags.PostBlockStarted) == 0) { base.Complete(userToken); return; } // At this point, IsCompleted is set and CompletedSynchronously is fixed. If it's synchronous, then we want to hold // the completion for the CaptureOrComplete() call to avoid the context flow. If not, we know CaptureOrComplete() has completed. if (CompletedSynchronously) { return; } ExecutionContext context = _Context; // If the context is being abandoned or wasn't captured (SuppressFlow, null AsyncCallback), just // complete regularly, as long as CaptureOrComplete() has finished. // if (userToken != IntPtr.Zero || context == null) { base.Complete(userToken); return; } ExecutionContext.Run((_Flags & StateFlags.ThreadSafeContextCopy) != 0 ? context.CreateCopy() : context, new ContextCallback(CompleteCallback), null); } private void CompleteCallback(object state) { GlobalLog.Print("ContextAwareResult#" + ValidationHelper.HashString(this) + "::CompleteCallback() Context set, calling callback."); base.Complete(IntPtr.Zero); } } } // File provided for Reference Use Only by Microsoft Corporation (c) 2007. //------------------------------------------------------------------------------ //// Copyright (c) Microsoft Corporation. All rights reserved. // //----------------------------------------------------------------------------- namespace System.Net { using System.Threading; using System.Security; using System.Security.Principal; using System.Security.Permissions; // // This is used by ContextAwareResult to cache callback closures between similar calls. Create one of these and // pass it in to FinishPostingAsyncOp() to prevent the context from being captured in every iteration of a looped async call. // // I thought about making the delegate and state into weak references, but decided against it because: // - The delegate is very likely to be abandoned by the user right after calling BeginXxx, making caching it useless. There's // no easy way to weakly reference just the target. // - We want to support identifying state via object.Equals() (especially value types), which means we need to keep a // reference to the original. Plus, if we're holding the target, might as well hold the state too. // The user will need to disable caching if they want their target/state to be instantly collected. // // For now the state is not included as part of the closure. It is too common a pattern (for example with socket receive) // to have several pending IOs differentiated by their state object. We don't want that pattern to break the cache. // internal class CallbackClosure { private AsyncCallback savedCallback; private ExecutionContext savedContext; internal CallbackClosure(ExecutionContext context, AsyncCallback callback) { if (callback != null) { savedCallback = callback; savedContext = context; } } internal bool IsCompatible(AsyncCallback callback) { if (callback == null || savedCallback == null) return false; // Delegates handle this ok. AsyncCallback is sealed and immutable, so if this succeeds, we are safe to use // the passed-in instance. if (!object.Equals(savedCallback, callback)) return false; return true; } internal AsyncCallback AsyncCallback { get { return savedCallback; } } internal ExecutionContext Context { get { return savedContext; } } } // // This class will ensure that the correct context is restored on the thread before invoking // a user callback. // internal class ContextAwareResult : LazyAsyncResult { [Flags] private enum StateFlags { None = 0x00, CaptureIdentity = 0x01, CaptureContext = 0x02, ThreadSafeContextCopy = 0x04, PostBlockStarted = 0x08, PostBlockFinished = 0x10, } // This needs to be volatile so it's sure to make it over to the completion thread in time. private volatile ExecutionContext _Context; private object _Lock; private StateFlags _Flags; #if !FEATURE_PAL private WindowsIdentity _Wi; #endif internal ContextAwareResult(object myObject, object myState, AsyncCallback myCallBack) : this(false, false, myObject, myState, myCallBack) { } // Setting captureIdentity enables the Identity property. This will be available even if ContextCopy isn't, either because // flow is suppressed or it wasn't needed. (If ContextCopy isn't available, Identity may or may not be. But if it is, it // should be used instead of ContextCopy for impersonation - ContextCopy might not include the identity.) // // Setting forceCaptureContext enables the ContextCopy property even when a null callback is specified. (The context is // always captured if a callback is given.) internal ContextAwareResult(bool captureIdentity, bool forceCaptureContext, object myObject, object myState, AsyncCallback myCallBack) : this(captureIdentity, forceCaptureContext, false, myObject, myState, myCallBack) { } internal ContextAwareResult(bool captureIdentity, bool forceCaptureContext, bool threadSafeContextCopy, object myObject, object myState, AsyncCallback myCallBack) : base(myObject, myState, myCallBack) { if (forceCaptureContext) { _Flags = StateFlags.CaptureContext; } if (captureIdentity) { _Flags |= StateFlags.CaptureIdentity; } if (threadSafeContextCopy) { _Flags |= StateFlags.ThreadSafeContextCopy; } } #if !FEATURE_PAL // Security: We need an assert for a call into WindowsIdentity.GetCurrent [SecurityPermissionAttribute(SecurityAction.Assert, Flags=SecurityPermissionFlag.ControlPrincipal)] private void SafeCaptureIdenity() { _Wi = WindowsIdentity.GetCurrent(); } #endif // // This can be used to establish a context during an async op for something like calling a delegate or demanding a permission. // May block briefly if the context is still being produced. // // Returns null if called from the posting thread. // internal ExecutionContext ContextCopy { get { GlobalLog.Assert(!InternalPeekCompleted || (_Flags & StateFlags.ThreadSafeContextCopy) != 0, "ContextAwareResult#{0}::ContextCopy|Called on completed result.", ValidationHelper.HashString(this)); if (InternalPeekCompleted) { throw new InvalidOperationException(SR.GetString(SR.net_completed_result)); } ExecutionContext context = _Context; if (context != null) { return context.CreateCopy(); } // Make sure the context was requested. GlobalLog.Assert(AsyncCallback != null || (_Flags & StateFlags.CaptureContext) != 0, "ContextAwareResult#{0}::ContextCopy|No context captured - specify a callback or forceCaptureContext.", ValidationHelper.HashString(this)); // Just use the lock to block. We might be on the thread that owns the lock which is great, it means we // don't need a context anyway. if ((_Flags & StateFlags.PostBlockFinished) == 0) { GlobalLog.Assert(_Lock != null, "ContextAwareResult#{0}::ContextCopy|Must lock (StartPostingAsyncOp()) { ... FinishPostingAsyncOp(); } when calling ContextCopy (unless it's only called after FinishPostingAsyncOp).", ValidationHelper.HashString(this)); lock (_Lock) { } } GlobalLog.Assert(!InternalPeekCompleted || (_Flags & StateFlags.ThreadSafeContextCopy) != 0, "ContextAwareResult#{0}::ContextCopy|Result became completed during call.", ValidationHelper.HashString(this)); if (InternalPeekCompleted) { throw new InvalidOperationException(SR.GetString(SR.net_completed_result)); } context = _Context; return context == null ? null : context.CreateCopy(); } } #if !FEATURE_PAL // // Just like ContextCopy. // internal WindowsIdentity Identity { get { GlobalLog.Assert(!InternalPeekCompleted || (_Flags & StateFlags.ThreadSafeContextCopy) != 0, "ContextAwareResult#{0}::Identity|Called on completed result.", ValidationHelper.HashString(this)); if (InternalPeekCompleted) { throw new InvalidOperationException(SR.GetString(SR.net_completed_result)); } if (_Wi != null) { return _Wi; } // Make sure the identity was requested. GlobalLog.Assert((_Flags & StateFlags.CaptureIdentity) != 0, "ContextAwareResult#{0}::Identity|No identity captured - specify captureIdentity.", ValidationHelper.HashString(this)); // Just use the lock to block. We might be on the thread that owns the lock which is great, it means we // don't need an identity anyway. if ((_Flags & StateFlags.PostBlockFinished) == 0) { GlobalLog.Assert(_Lock != null, "ContextAwareResult#{0}::Identity|Must lock (StartPostingAsyncOp()) { ... FinishPostingAsyncOp(); } when calling Identity (unless it's only called after FinishPostingAsyncOp).", ValidationHelper.HashString(this)); lock (_Lock) { } } GlobalLog.Assert(!InternalPeekCompleted || (_Flags & StateFlags.ThreadSafeContextCopy) != 0, "ContextAwareResult#{0}::Identity|Result became completed during call.", ValidationHelper.HashString(this)); if (InternalPeekCompleted) { throw new InvalidOperationException(SR.GetString(SR.net_completed_result)); } return _Wi; } } #endif #if DEBUG // Want to be able to verify that the Identity was requested. If it was requested but isn't available // on the Identity property, it's either available via ContextCopy or wasn't needed (synchronous). internal bool IdentityRequested { get { return (_Flags & StateFlags.CaptureIdentity) != 0; } } #endif internal object StartPostingAsyncOp() { return StartPostingAsyncOp(true); } // // If ContextCopy or Identity will be used, the return value should be locked until FinishPostingAsyncOp() is called // or the operation has been aborted (e.g. by BeginXxx throwing). Otherwise, this can be called with false to prevent the lock // object from being created. // internal object StartPostingAsyncOp(bool lockCapture) { GlobalLog.Assert(!InternalPeekCompleted, "ContextAwareResult#{0}::StartPostingAsyncOp|Called on completed result.", ValidationHelper.HashString(this)); DebugProtectState(true); _Lock = lockCapture ? new object() : null; _Flags |= StateFlags.PostBlockStarted; return _Lock; } // // Call this when returning control to the user. // internal bool FinishPostingAsyncOp() { // Ignore this call if StartPostingAsyncOp() failed or wasn't called, or this has already been called. if ((_Flags & (StateFlags.PostBlockStarted | StateFlags.PostBlockFinished)) != StateFlags.PostBlockStarted) { return false; } _Flags |= StateFlags.PostBlockFinished; ExecutionContext cachedContext = null; return CaptureOrComplete(ref cachedContext, false); } // // Call this when returning control to the user. Allows a cached Callback Closure to be supplied and used // as appropriate, and replaced with a new one. // internal bool FinishPostingAsyncOp(ref CallbackClosure closure) { // Ignore this call if StartPostingAsyncOp() failed or wasn't called, or this has already been called. if ((_Flags & (StateFlags.PostBlockStarted | StateFlags.PostBlockFinished)) != StateFlags.PostBlockStarted) { return false; } _Flags |= StateFlags.PostBlockFinished; // Need a copy of this ref argument since it can be used in many of these calls simultaneously. CallbackClosure closureCopy = closure; ExecutionContext cachedContext; if (closureCopy == null) { cachedContext = null; } else { if (!closureCopy.IsCompatible(AsyncCallback)) { // Clear the cache as soon as a method is called with incompatible parameters. closure = null; cachedContext = null; } else { // If it succeeded, we want to replace our context/callback with the one from the closure. // Using the closure's instance of the callback is probably overkill, but safer. AsyncCallback = closureCopy.AsyncCallback; cachedContext = closureCopy.Context; } } bool calledCallback = CaptureOrComplete(ref cachedContext, true); // Set up new cached context if we didn't use the previous one. if (closure == null && AsyncCallback != null && cachedContext != null) { closure = new CallbackClosure(cachedContext, AsyncCallback); } return calledCallback; } /* enable when needed // // Use this to block until FinishPostingAsyncOp() completes. Must check for null. // internal object PostingLock { get { return _Lock; } } // // Call this if you want to cancel any flowing. // internal void InvokeCallbackWithoutContext(object result) { ProtectedInvokeCallback(result, (IntPtr) 1); } */ // protected override void Cleanup() { base.Cleanup(); GlobalLog.Print("ContextAwareResult#" + ValidationHelper.HashString(this) + "::Cleanup()"); #if !FEATURE_PAL if (_Wi != null) { _Wi.Dispose(); _Wi = null; } #endif } // // This must be called right before returning the result to the user. It might call the callback itself, // to avoid flowing context. Even if the operation completes before this call, the callback won't have been // called. // // Returns whether the operation completed [....] or not. // private bool CaptureOrComplete(ref ExecutionContext cachedContext, bool returnContext) { GlobalLog.Assert((_Flags & StateFlags.PostBlockStarted) != 0, "ContextAwareResult#{0}::CaptureOrComplete|Called without calling StartPostingAsyncOp.", ValidationHelper.HashString(this)); // See if we're going to need to capture the context. bool capturingContext = AsyncCallback != null || (_Flags & StateFlags.CaptureContext) != 0; #if !FEATURE_PAL // Peek if we've already completed, but don't fix CompletedSynchronously yet // Capture the identity if requested, unless we're going to capture the context anyway, unless // capturing the context won't be sufficient. if ((_Flags & StateFlags.CaptureIdentity) != 0 && !InternalPeekCompleted && (!capturingContext || SecurityContext.IsWindowsIdentityFlowSuppressed())) { GlobalLog.Print("ContextAwareResult#" + ValidationHelper.HashString(this) + "::CaptureOrComplete() starting identity capture"); SafeCaptureIdenity(); } #endif // No need to flow if there's no callback, unless it's been specifically requested. // Note that Capture() can return null, for example if SuppressFlow() is in effect. if (capturingContext && !InternalPeekCompleted) { GlobalLog.Print("ContextAwareResult#" + ValidationHelper.HashString(this) + "::CaptureOrComplete() starting capture"); if (cachedContext == null) { cachedContext = ExecutionContext.Capture(); } if (cachedContext != null) { if (!returnContext) { _Context = cachedContext; cachedContext = null; } else { _Context = cachedContext.CreateCopy(); } } GlobalLog.Print("ContextAwareResult#" + ValidationHelper.HashString(this) + "::CaptureOrComplete() _Context:" + ValidationHelper.HashString(_Context)); } else { // Otherwise we have to have completed synchronously, or not needed the context. GlobalLog.Print("ContextAwareResult#" + ValidationHelper.HashString(this) + "::CaptureOrComplete() skipping capture"); cachedContext = null; GlobalLog.Assert(AsyncCallback == null || CompletedSynchronously, "ContextAwareResult#{0}::CaptureOrComplete|Didn't capture context, but didn't complete synchronously!", ValidationHelper.HashString(this)); } // Now we want to see for sure what to do. We might have just captured the context for no reason. // This has to be the first time the state has been queried "for real" (apart from InvokeCallback) // to guarantee synchronization with Complete() (otherwise, Complete() could try to call the // callback without the context having been gotten). DebugProtectState(false); if (CompletedSynchronously) { GlobalLog.Print("ContextAwareResult#" + ValidationHelper.HashString(this) + "::CaptureOrComplete() completing synchronously"); base.Complete(IntPtr.Zero); return true; } return false; } // // Is guaranteed to be called only once. If called with a non-zero userToken, the context is not flowed. // protected override void Complete(IntPtr userToken) { GlobalLog.Print("ContextAwareResult#" + ValidationHelper.HashString(this) + "::Complete() _Context(set):" + (_Context != null).ToString() + " userToken:" + userToken.ToString()); // If no flowing, just complete regularly. if ((_Flags & StateFlags.PostBlockStarted) == 0) { base.Complete(userToken); return; } // At this point, IsCompleted is set and CompletedSynchronously is fixed. If it's synchronous, then we want to hold // the completion for the CaptureOrComplete() call to avoid the context flow. If not, we know CaptureOrComplete() has completed. if (CompletedSynchronously) { return; } ExecutionContext context = _Context; // If the context is being abandoned or wasn't captured (SuppressFlow, null AsyncCallback), just // complete regularly, as long as CaptureOrComplete() has finished. // if (userToken != IntPtr.Zero || context == null) { base.Complete(userToken); return; } ExecutionContext.Run((_Flags & StateFlags.ThreadSafeContextCopy) != 0 ? context.CreateCopy() : context, new ContextCallback(CompleteCallback), null); } private void CompleteCallback(object state) { GlobalLog.Print("ContextAwareResult#" + ValidationHelper.HashString(this) + "::CompleteCallback() Context set, calling callback."); base.Complete(IntPtr.Zero); } } } // File provided for Reference Use Only by Microsoft Corporation (c) 2007.
Link Menu

This book is available now!
Buy at Amazon US or
Buy at Amazon UK
- DataTrigger.cs
- ExpressionEditorAttribute.cs
- JoinQueryOperator.cs
- SchemaImporterExtension.cs
- ValueOfAction.cs
- SelectionProviderWrapper.cs
- ProcessHost.cs
- IDispatchConstantAttribute.cs
- SessionStateModule.cs
- HandlerBase.cs
- PolyBezierSegment.cs
- UriSection.cs
- CqlIdentifiers.cs
- ChannelEndpointElement.cs
- IPCCacheManager.cs
- ToolBarPanel.cs
- ImageListStreamer.cs
- AttachedPropertyBrowsableForChildrenAttribute.cs
- ArithmeticException.cs
- StorageComplexTypeMapping.cs
- CompiledXpathExpr.cs
- RealizationDrawingContextWalker.cs
- ADConnectionHelper.cs
- InkSerializer.cs
- ServiceRoute.cs
- ExeConfigurationFileMap.cs
- UnsafeNativeMethods.cs
- XmlDataContract.cs
- TransactionFormatter.cs
- DispatcherHooks.cs
- DisplayInformation.cs
- CriticalFileToken.cs
- UserPreferenceChangingEventArgs.cs
- ExtendedPropertyDescriptor.cs
- OlePropertyStructs.cs
- PipeStream.cs
- Pair.cs
- SafeRightsManagementSessionHandle.cs
- CallbackValidatorAttribute.cs
- SystemInformation.cs
- SoapInteropTypes.cs
- AccessViolationException.cs
- DocumentGridPage.cs
- formatstringdialog.cs
- ContractNamespaceAttribute.cs
- RowType.cs
- UserControlParser.cs
- ADMembershipUser.cs
- PriorityQueue.cs
- ApplicationGesture.cs
- KeyedPriorityQueue.cs
- RichTextBox.cs
- CapabilitiesPattern.cs
- ServiceOperationParameter.cs
- HttpWrapper.cs
- EventMappingSettingsCollection.cs
- TextEffectCollection.cs
- EdmEntityTypeAttribute.cs
- DbDataSourceEnumerator.cs
- BitmapMetadataEnumerator.cs
- FontSizeConverter.cs
- ImportContext.cs
- ControlAdapter.cs
- UndoManager.cs
- PasswordPropertyTextAttribute.cs
- OdbcCommand.cs
- ScriptControlManager.cs
- HuffmanTree.cs
- DocumentSequence.cs
- Directory.cs
- ToolStripDropDown.cs
- bindurihelper.cs
- ContractTypeNameCollection.cs
- GridPatternIdentifiers.cs
- Enlistment.cs
- TextMessageEncodingBindingElement.cs
- Math.cs
- SQLBinary.cs
- DataGridViewCellEventArgs.cs
- X500Name.cs
- CharStorage.cs
- formatter.cs
- Serializer.cs
- Instrumentation.cs
- ipaddressinformationcollection.cs
- BitmapEffectRenderDataResource.cs
- BindingOperations.cs
- Win32PrintDialog.cs
- ImageAutomationPeer.cs
- hebrewshape.cs
- Vector3DAnimation.cs
- MobileSysDescriptionAttribute.cs
- PrivilegeNotHeldException.cs
- DeflateStream.cs
- IncomingWebResponseContext.cs
- ConcatQueryOperator.cs
- ActiveXSerializer.cs
- HashCodeCombiner.cs
- CannotUnloadAppDomainException.cs
- ReflectionUtil.cs