File: AsyncResult.cs
Web Access
Project: src\src\System.Private.ServiceModel\tests\Scenarios\Extensibility\MessageInterceptor\Extensibility.MessageInterceptor.IntegrationTests.csproj (Extensibility.MessageInterceptor.IntegrationTests)
// Licensed to the .NET Foundation under one or more agreements.
// The .NET Foundation licenses this file to you under the MIT license.
// See the LICENSE file in the project root for more information.
 
 
using System;
using System.Diagnostics;
using System.Threading;
 
/// <summary>
/// A generic base class for IAsyncResult implementations
/// that wraps a ManualResetEvent.
/// </summary>
internal abstract class AsyncResult : IAsyncResult
{
    private AsyncCallback _callback;
    private object _state;
    private bool _completedSynchronously;
    private bool _endCalled;
    private Exception _exception;
    private bool _isCompleted;
    private ManualResetEvent _manualResetEvent;
    private object _thisLock;
 
    protected AsyncResult(AsyncCallback callback, object state)
    {
        this._callback = callback;
        this._state = state;
        this._thisLock = new object();
    }
 
    public object AsyncState
    {
        get
        {
            return _state;
        }
    }
 
    public WaitHandle AsyncWaitHandle
    {
        get
        {
            if (_manualResetEvent != null)
            {
                return _manualResetEvent;
            }
 
            lock (ThisLock)
            {
                if (_manualResetEvent == null)
                {
                    _manualResetEvent = new ManualResetEvent(_isCompleted);
                }
            }
 
            return _manualResetEvent;
        }
    }
 
    public bool CompletedSynchronously
    {
        get
        {
            return _completedSynchronously;
        }
    }
 
    public bool IsCompleted
    {
        get
        {
            return _isCompleted;
        }
    }
 
    private object ThisLock
    {
        get
        {
            return this._thisLock;
        }
    }
 
    // Call this version of complete when your asynchronous operation is complete.  This will update the state
    // of the operation and notify the callback.
    protected void Complete(bool completedSynchronously)
    {
        if (_isCompleted)
        {
            // It is a bug to call Complete twice.
            throw new InvalidOperationException("Cannot call Complete twice");
        }
 
        this._completedSynchronously = completedSynchronously;
 
        if (completedSynchronously)
        {
            // If we completedSynchronously, then there is no chance that the manualResetEvent was created so
            // we do not need to worry about a race condition.
            Debug.Assert(this._manualResetEvent == null, "No ManualResetEvent should be created for a synchronous AsyncResult.");
            this._isCompleted = true;
        }
        else
        {
            lock (ThisLock)
            {
                this._isCompleted = true;
                if (this._manualResetEvent != null)
                {
                    this._manualResetEvent.Set();
                }
            }
        }
 
        // If the callback throws, there is a bug in the callback implementation
        if (_callback != null)
        {
            _callback(this);
        }
    }
 
    // 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.
    protected void Complete(bool completedSynchronously, Exception exception)
    {
        this._exception = exception;
        Complete(completedSynchronously);
    }
 
    // 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.
    protected static TAsyncResult End<TAsyncResult>(IAsyncResult result)
        where TAsyncResult : AsyncResult
    {
        if (result == null)
        {
            throw new ArgumentNullException("result");
        }
 
        TAsyncResult asyncResult = result as TAsyncResult;
 
        if (asyncResult == null)
        {
            throw new ArgumentException("Invalid async result.", "result");
        }
 
        if (asyncResult._endCalled)
        {
            throw new InvalidOperationException("Async object already ended.");
        }
 
        asyncResult._endCalled = true;
 
        if (!asyncResult._isCompleted)
        {
            asyncResult.AsyncWaitHandle.WaitOne();
        }
 
        if (asyncResult._manualResetEvent != null)
        {
            asyncResult._manualResetEvent.Dispose();
        }
 
        if (asyncResult._exception != null)
        {
            throw asyncResult._exception;
        }
 
        return asyncResult;
    }
}
 
//An AsyncResult that completes as soon as it is instantiated.
internal class CompletedAsyncResult : AsyncResult
{
    public CompletedAsyncResult(AsyncCallback callback, object state)
        : base(callback, state)
    {
        Complete(true);
    }
 
    public static void End(IAsyncResult result)
    {
        AsyncResult.End<CompletedAsyncResult>(result);
    }
}
 
//A strongly typed AsyncResult
internal abstract class TypedAsyncResult<T> : AsyncResult
{
    private T _data;
 
    protected TypedAsyncResult(AsyncCallback callback, object state)
        : base(callback, state)
    {
    }
 
    public T Data
    {
        get { return _data; }
    }
 
    protected void Complete(T data, bool completedSynchronously)
    {
        this._data = data;
        Complete(completedSynchronously);
    }
 
    public static T End(IAsyncResult result)
    {
        TypedAsyncResult<T> typedResult = AsyncResult.End<TypedAsyncResult<T>>(result);
        return typedResult.Data;
    }
}
 
//A strongly typed AsyncResult that completes as soon as it is instantiated.
internal class TypedCompletedAsyncResult<T> : TypedAsyncResult<T>
{
    public TypedCompletedAsyncResult(T data, AsyncCallback callback, object state)
        : base(callback, state)
    {
        Complete(data, true);
    }
 
    public new static T End(IAsyncResult result)
    {
        TypedCompletedAsyncResult<T> completedResult = result as TypedCompletedAsyncResult<T>;
        if (completedResult == null)
        {
            throw new ArgumentException("Invalid async result.", "result");
        }
 
        return TypedAsyncResult<T>.End(completedResult);
    }
}