internal void OnAsyncCompletion(int bytesCompleted, int hresult, IntPtr pAsyncCompletionContext) {
     // clear _asyncResultBase because when we call Complete the user's callback
     // may begin another async operation
     AsyncResultBase ar = _asyncResultBase;
     _asyncResultBase = null;
     ar.Complete(bytesCompleted, hresult, pAsyncCompletionContext, synchronous: false);
 }
        // Begin an asynchronous read of the request entity body.  To read the entire entity, invoke
        // repeatedly until total bytes read is equal to Request.ContentLength or EndRead indicates
        // that zero bytes were read.  If Request.ContentLength is zero and the request is chunked,
        // then invoke repeatedly until EndRead indicates that zero bytes were read.
        //
        // If an error occurs and the client is no longer connected, an HttpException will be thrown.
        //
        // This implements Stream.BeginRead, and as such, should throw
        // exceptions as described on MSDN when errors occur.
        public override IAsyncResult BeginRead(byte[] buffer, int offset, int count, AsyncCallback callback, Object state) {
            // Do as Stream does.
            if (buffer == null)
                throw new ArgumentNullException("buffer");
            if (offset < 0)
                throw new ArgumentOutOfRangeException("offset");
            if (count < 0)
                throw new ArgumentOutOfRangeException("count");
            if (buffer.Length - offset < count)
                throw new ArgumentException(SR.GetString(SR.InvalidOffsetOrCount, "offset", "count"));

            ReadAsyncResult ar = new ReadAsyncResult(callback, state, buffer, offset, count, updatePerfCounter: true);

            if (count == 0) {
                ar.Complete(0, HResults.S_OK, IntPtr.Zero, synchronous: true);
                return ar;
            }

            // we only allow one async operation at a time
            if (Interlocked.CompareExchange(ref _asyncResultBase, ar, null) != null)
                throw new InvalidOperationException(SR.GetString(SR.Async_operation_pending));

            // initiate async operation here
            bool fAsync = true;
            int bytesRead = 0;
            IntPtr ppAsyncReceiveBuffer;
            int hresult = IIS.MgdReadEntityBody(_context,
                                                null, // for async the data is copied from a native buffer to avoid pinning
                                                0, // for async, offset is ignored
                                                count, // number of bytes to read
                                                fAsync,
                                                out bytesRead,
                                                out ppAsyncReceiveBuffer);

            if (hresult < 0) {
                _asyncResultBase = null;
                // treat every error as if the client disconnected
                IncrementRequestsDisconnected();
                throw new HttpException(SR.GetString(SR.ClientDisconnected), hresult);
            }
            // if we completed synchronously, then ppAsyncReceiveBuffer will be non-null
            else if (ppAsyncReceiveBuffer != IntPtr.Zero) {
                _asyncResultBase = null;
                ar.Complete(bytesRead, HResults.S_OK, ppAsyncReceiveBuffer, synchronous: true);
                return ar;
            }
            else {
                return ar;
            }
        }
        // Begin an asynchronous flush of the response.  To support this, the worker request buffers
        // the status, headers, and resonse body until an asynchronous flush operation is initiated.
        public override IAsyncResult BeginFlush(AsyncCallback callback, Object state) {
            if (_context == IntPtr.Zero) {
                throw new InvalidOperationException();
            }

            FlushAsyncResult ar = new FlushAsyncResult(callback, state);

            // we only allow one async operation at a time
            if (Interlocked.CompareExchange(ref _asyncResultBase, ar, null) != null)
                throw new InvalidOperationException(SR.GetString(SR.Async_operation_pending));

            // initiate async operation here
            bool async = true;
            bool completedSynchronously;
            int hresult = IIS.MgdExplicitFlush(_context, async, out completedSynchronously);

            if (hresult < 0) {
                _asyncResultBase = null;
                // treat every error as if the client disconnected
                IncrementRequestsDisconnected();
                throw new HttpException(SR.GetString(SR.ClientDisconnected), hresult);
            }
            else if (completedSynchronously) {
                _asyncResultBase = null;
                ar.Complete(0, HResults.S_OK, IntPtr.Zero, synchronous: true);
                return ar;
            }
            else {
                return ar;
            }
        }