e79aa3c0ed
Former-commit-id: a2155e9bd80020e49e72e86c44da02a8ac0e57a4
290 lines
9.4 KiB
C#
290 lines
9.4 KiB
C#
//------------------------------------------------------------
|
|
// Copyright (c) Microsoft Corporation. All rights reserved.
|
|
//------------------------------------------------------------
|
|
|
|
namespace System.IdentityModel
|
|
{
|
|
using System;
|
|
using System.Diagnostics;
|
|
using System.Threading;
|
|
using System.Runtime;
|
|
|
|
/// <summary>
|
|
/// Base class for common AsyncResult programming scenarios.
|
|
/// </summary>
|
|
public abstract class AsyncResult : IAsyncResult, IDisposable
|
|
{
|
|
/// <summary>
|
|
/// 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.
|
|
/// </summary>
|
|
/// <param name="result">The <see cref="IAsyncResult"/> representing the status of an asynchronous operation.</param>
|
|
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;
|
|
|
|
/// <summary>
|
|
/// Constructor for async results that do not need a callback or state.
|
|
/// </summary>
|
|
protected AsyncResult()
|
|
: this(null, null)
|
|
{
|
|
}
|
|
|
|
/// <summary>
|
|
/// Constructor for async results that do not need a callback.
|
|
/// </summary>
|
|
/// <param name="state">A user-defined object that qualifies or contains information about an asynchronous operation.</param>
|
|
protected AsyncResult(object state)
|
|
: this(null, state)
|
|
{
|
|
}
|
|
|
|
/// <summary>
|
|
/// Constructor for async results that need a callback and a state.
|
|
/// </summary>
|
|
/// <param name="callback">The method to be called when the async operation completes.</param>
|
|
/// <param name="state">A user-defined object that qualifies or contains information about an asynchronous operation.</param>
|
|
protected AsyncResult(AsyncCallback callback, object state)
|
|
{
|
|
this.thisLock = new object();
|
|
this.callback = callback;
|
|
this.state = state;
|
|
}
|
|
|
|
/// <summary>
|
|
/// Finalizer for AsyncResult.
|
|
/// </summary>
|
|
~AsyncResult()
|
|
{
|
|
Dispose(false);
|
|
}
|
|
|
|
/// <summary>
|
|
/// Call this version of complete when your asynchronous operation is complete. This will update the state
|
|
/// of the operation and notify the callback.
|
|
/// </summary>
|
|
/// <param name="completedSynchronously">True if the asynchronous operation completed synchronously.</param>
|
|
protected void Complete(bool completedSynchronously)
|
|
{
|
|
Complete(completedSynchronously, null);
|
|
}
|
|
|
|
/// <summary>
|
|
/// 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.
|
|
/// </summary>
|
|
/// <param name="completedSynchronously">True if the asynchronous operation completed synchronously.</param>
|
|
/// <param name="exception">The exception during the processing of the asynchronous operation.</param>
|
|
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));
|
|
}
|
|
}
|
|
|
|
/// <summary>
|
|
/// Disposes of unmanaged resources held by the AsyncResult.
|
|
/// </summary>
|
|
/// <param name="isExplicitDispose">True if this is an explicit call to Dispose.</param>
|
|
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
|
|
|
|
/// <summary>
|
|
/// Gets the user-defined state information that was passed to the Begin method.
|
|
/// </summary>
|
|
public object AsyncState
|
|
{
|
|
get
|
|
{
|
|
return state;
|
|
}
|
|
}
|
|
|
|
/// <summary>
|
|
/// Gets the wait handle of the async event.
|
|
/// </summary>
|
|
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;
|
|
}
|
|
}
|
|
|
|
/// <summary>
|
|
/// Gets a value that indicates whether the asynchronous operation completed synchronously.
|
|
/// </summary>
|
|
public bool CompletedSynchronously
|
|
{
|
|
get
|
|
{
|
|
return completedSync;
|
|
}
|
|
}
|
|
|
|
/// <summary>
|
|
/// Gets a value that indicates whether the asynchronous operation has completed.
|
|
/// </summary>
|
|
public bool IsCompleted
|
|
{
|
|
get
|
|
{
|
|
return completed;
|
|
}
|
|
}
|
|
|
|
#endregion
|
|
|
|
#region IDisposable Members
|
|
|
|
/// <summary>
|
|
/// Disposes this object
|
|
/// </summary>
|
|
public void Dispose()
|
|
{
|
|
Dispose(true);
|
|
|
|
GC.SuppressFinalize(this);
|
|
}
|
|
|
|
#endregion
|
|
}
|
|
}
|
|
|