//------------------------------------------------------------ // Copyright (c) Microsoft Corporation. All rights reserved. //------------------------------------------------------------ namespace System.IdentityModel { using System; using System.Diagnostics; using System.Threading; using System.Runtime; /// /// Base class for common AsyncResult programming scenarios. /// public abstract class AsyncResult : IAsyncResult, IDisposable { /// /// End should be called when the End function for the asynchronous operation is complete. It /// ensures the asynchronous operation is complete, and does some common validation. /// /// The representing the status of an asynchronous operation. public static void End(IAsyncResult result) { if (result == null) throw DiagnosticUtility.ExceptionUtility.ThrowHelperArgumentNull("result"); AsyncResult asyncResult = result as AsyncResult; if (asyncResult == null) throw DiagnosticUtility.ExceptionUtility.ThrowHelperError(new ArgumentException(SR.GetString(SR.ID4001), "result")); if (asyncResult.endCalled) throw DiagnosticUtility.ExceptionUtility.ThrowHelperError(new InvalidOperationException(SR.GetString(SR.ID4002))); asyncResult.endCalled = true; if (!asyncResult.completed) asyncResult.AsyncWaitHandle.WaitOne(); if (asyncResult.resetEvent != null) ((IDisposable)asyncResult.resetEvent).Dispose(); if (asyncResult.exception != null) throw asyncResult.exception; } AsyncCallback callback; bool completed; bool completedSync; bool disposed; bool endCalled; Exception exception; ManualResetEvent resetEvent; object state; object thisLock; /// /// Constructor for async results that do not need a callback or state. /// protected AsyncResult() : this(null, null) { } /// /// Constructor for async results that do not need a callback. /// /// A user-defined object that qualifies or contains information about an asynchronous operation. protected AsyncResult(object state) : this(null, state) { } /// /// Constructor for async results that need a callback and a state. /// /// The method to be called when the async operation completes. /// A user-defined object that qualifies or contains information about an asynchronous operation. protected AsyncResult(AsyncCallback callback, object state) { this.thisLock = new object(); this.callback = callback; this.state = state; } /// /// Finalizer for AsyncResult. /// ~AsyncResult() { Dispose(false); } /// /// Call this version of complete when your asynchronous operation is complete. This will update the state /// of the operation and notify the callback. /// /// True if the asynchronous operation completed synchronously. protected void Complete(bool completedSynchronously) { Complete(completedSynchronously, null); } /// /// Call this version of complete if you raise an exception during processing. In addition to notifying /// the callback, it will capture the exception and store it to be thrown during AsyncResult.End. /// /// True if the asynchronous operation completed synchronously. /// The exception during the processing of the asynchronous operation. protected void Complete(bool completedSynchronously, Exception exception) { if (completed == true) { // it is a bug to call complete twice throw DiagnosticUtility.ExceptionUtility.ThrowHelperError(new AsynchronousOperationException(SR.GetString(SR.ID4005))); } completedSync = completedSynchronously; this.exception = exception; if (completedSynchronously) { // // No event should be set for synchronous completion // completed = true; Fx.Assert(resetEvent == null, SR.GetString(SR.ID8025)); } else { // // Complete asynchronously // lock (thisLock) { completed = true; if (resetEvent != null) resetEvent.Set(); } } // // finally call the call back. Note, we are expecting user's callback to handle the exception // so, if the callback throw exception, all we can do is burn and crash. // try { if (callback != null) callback(this); } catch (ThreadAbortException) { // // The thread running the callback is being aborted. We ignore this case. // } catch (AsynchronousOperationException) { throw; } #pragma warning suppress 56500 catch (Exception unhandledException) { // // The callback raising an exception is equivalent to Main raising an exception w/out a catch. // We should just throw it back. We should log the exception somewhere. // // Because the stack trace gets lost on a rethrow, we're wrapping it in a generic exception // so the stack trace is preserved. // throw DiagnosticUtility.ExceptionUtility.ThrowHelperError(new AsynchronousOperationException(SR.GetString(SR.ID4003), unhandledException)); } } /// /// Disposes of unmanaged resources held by the AsyncResult. /// /// True if this is an explicit call to Dispose. protected virtual void Dispose(bool isExplicitDispose) { if (!disposed) { if (isExplicitDispose) { lock (thisLock) { if (!disposed) { // // Mark disposed // disposed = true; // // Called explicitly to close the object // if (resetEvent != null) resetEvent.Close(); } } } else { // // Called for finalization // } } } #region IAsyncResult implementation /// /// Gets the user-defined state information that was passed to the Begin method. /// public object AsyncState { get { return state; } } /// /// Gets the wait handle of the async event. /// public virtual WaitHandle AsyncWaitHandle { get { if (resetEvent == null) { bool savedCompleted = completed; lock (thisLock) { if (resetEvent == null) resetEvent = new ManualResetEvent(completed); } if (!savedCompleted && completed) resetEvent.Set(); } return resetEvent; } } /// /// Gets a value that indicates whether the asynchronous operation completed synchronously. /// public bool CompletedSynchronously { get { return completedSync; } } /// /// Gets a value that indicates whether the asynchronous operation has completed. /// public bool IsCompleted { get { return completed; } } #endregion #region IDisposable Members /// /// Disposes this object /// public void Dispose() { Dispose(true); GC.SuppressFinalize(this); } #endregion } }