1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 245 246 247 248 249 250 251 252 253 254 255 256 257 258 259 260 261 262 263 264 265 266 267 268 269 270 271 272 273 274 275 276 277 278 279 280 281 282 283 284 285 286 287 288 289
|
//------------------------------------------------------------
// 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
}
}
|