QueryAsyncResult.cs source code in C# .NET

Source code for the .NET framework in C#

                        

Code:

/ Dotnetfx_Win7_3.5.1 / Dotnetfx_Win7_3.5.1 / 3.5.1 / DEVDIV / depot / DevDiv / releases / Orcas / NetFXw7 / ndp / fx / src / DataWeb / Client / System / Data / Services / Client / QueryAsyncResult.cs / 2 / QueryAsyncResult.cs

                            //---------------------------------------------------------------------- 
// 
//      Copyright (c) Microsoft Corporation.  All rights reserved.
// 
//  
// query object
//  
//--------------------------------------------------------------------- 

namespace System.Data.Services.Client 
{
    using System;
    using System.Collections;
    using System.Collections.Generic; 
    using System.Diagnostics;
    using System.IO; 
#if !ASTORIA_LIGHT // Data.Services http stack 
    using System.Net;
#else 
    using System.Data.Services.Http;
#endif

    ///  
    /// Wrapper HttpWebRequest & HttWebResponse
    ///  
    internal class QueryAsyncResult : BaseAsyncResult 
    {
        /// Originating service request 
        internal readonly DataServiceRequest ServiceRequest;

        /// Originating WebRequest
        internal readonly HttpWebRequest Request; 

        /// reusuable async copy buffer 
        private static byte[] reusableAsyncCopyBuffer; 

        /// content to write to request stream 
        private MemoryStream requestStreamContent;

        /// active web request stream
        private Stream requestStream; 

        /// web response, closed when completed 
        private HttpWebResponse httpWebResponse; 

        /// async response stream, closed when completed 
        private Stream asyncResponseStream;

        /// buffer when copying async stream to response stream cache
        private byte[] asyncStreamCopyBuffer; 

        /// response stream, returned to other parts of the system 
        /// with async, the asyncResponseStream is copied into this stream 
        private Stream responseStream;
 
        /// copy of HttpWebResponse.ContentType
        private string contentType;

        /// copy of HttpWebResponse.ContentLength 
        private long contentLength;
 
        /// copy of HttpWebResponse.StatusCode 
        private HttpStatusCode statusCode;
 
        /// 
        /// does this own the response stream or does the container of this QueryAsyncResult?
        /// 
        private bool responseStreamOwner; 

        ///  
        /// if the BeginRead has been called with asyncStreamCopyBuffer, but EndRead has not. 
        /// do not return the buffer to general pool if any question of it being in use.
        ///  
        private bool usingBuffer;

#if StreamContainsBuffer
        /// does the responseStream contain the asyncStreamCopyBuffer? 
        /// optimize reading in to the async buffer without copying into separate response stream
        private bool responseStreamIsCopyBuffer; 
#endif 

        /// If CompletedSynchronously and asyncCompleteStep didn't increment, then underlying implementation lied. 
        private int asyncCompleteStep;

        /// constructor
        /// source object of async request 
        /// async method name on source object
        /// Originating serviceRequest 
        /// Originating WebRequest 
        /// user callback
        /// user state 
        internal QueryAsyncResult(object source, string method, DataServiceRequest serviceRequest, HttpWebRequest request, AsyncCallback callback, object state)
            : base(source, method, callback, state)
        {
            Debug.Assert(null != request, "null request"); 
            this.ServiceRequest = serviceRequest;
            this.Request = request; 
        } 

        #region HttpResponse wrapper - ContentLength, ContentType, StatusCode 

        /// HttpWebResponse.ContentLength
        internal long ContentLength
        { 
            get { return this.contentLength; }
        } 
 
        /// HttpWebResponse.ContentType
        internal string ContentType 
        {
            get { return this.contentType; }
        }
 
        /// HttpWebResponse.StatusCode
        internal HttpStatusCode StatusCode 
        { 
            get { return this.statusCode; }
        } 

        #endregion

        ///  
        /// Ends the asynchronous query request.
        ///  
        /// Element type of the result. 
        /// Source object of async request.
        /// The asyncResult being ended. 
        /// Data service response.
        internal static QueryAsyncResult EndExecute(object source, IAsyncResult asyncResult)
        {
            QueryAsyncResult response = null; 

            try 
            { 
                response = BaseAsyncResult.EndExecute(source, "Execute", asyncResult);
            } 
            catch (InvalidOperationException ex)
            {
                response = asyncResult as QueryAsyncResult;
                Debug.Assert(response != null, "response != null, BaseAsyncResult.EndExecute() would have thrown a different exception otherwise."); 

                QueryOperationResponse operationResponse = response.GetResponse(null, typeof(TElement)); 
                if (operationResponse != null) 
                {
                    operationResponse.Error = ex; 
                    throw new DataServiceQueryException(Strings.DataServiceException_GeneralError, ex, operationResponse);
                }

                throw; 
            }
 
            return response; 
        }
 
        /// wrapper for HttpWebResponse.GetResponseStream
        /// stream
        internal Stream GetResponseStream()
        { 
            return this.responseStream;
        } 
 
        /// start the asynchronous request
        /// content stream to send asynchronously in the request 
        internal void BeginExecute(MemoryStream requestContent)
        {
            try
            { 
                int step = ++this.asyncCompleteStep;
 
                IAsyncResult asyncResult; 
                if ((null != requestContent) && (0 < requestContent.Length))
                { 
                    requestContent.Position = 0;
                    this.requestStreamContent = requestContent;
                    this.Request.ContentLength = requestContent.Length;
                    asyncResult = this.Request.BeginGetRequestStream(QueryAsyncResult.AsyncEndGetRequestStream, this); 
                }
                else 
                { 
                    asyncResult = this.Request.BeginGetResponse(QueryAsyncResult.AsyncEndGetResponse, this);
                } 

                this.CompletedSynchronously &= asyncResult.CompletedSynchronously && (step < this.asyncCompleteStep);
            }
            catch (Exception e) 
            {
                this.HandleFailure(e); 
                throw; 
            }
            finally 
            {
                this.HandleCompleted();
            }
 
            Debug.Assert(!this.CompletedSynchronously || this.IsCompleted, "if CompletedSynchronously then MUST IsCompleted");
        } 
 
#if !ASTORIA_LIGHT
        /// Synchronous web request 
        /// content stream to send in the request
        internal void Execute(MemoryStream requestContent)
        {
            try 
            {
                if ((null != requestContent) && (0 < requestContent.Length)) 
                { 
                    using (System.IO.Stream stream = Util.NullCheck(this.Request.GetRequestStream(), InternalError.InvalidGetRequestStream))
                    { 
                        byte[] buffer = requestContent.GetBuffer();
                        int bufferOffset = checked((int)requestContent.Position);
                        int bufferLength = checked((int)requestContent.Length) - bufferOffset;
 
                        // the following is useful in the debugging Immediate Window
                        // string x = System.Text.Encoding.UTF8.GetString(buffer, bufferOffset, bufferLength); 
                        stream.Write(buffer, bufferOffset, bufferLength); 
                    }
                } 

                HttpWebResponse response = null;
                try
                { 
                    response = (HttpWebResponse)this.Request.GetResponse();
                } 
                catch (WebException ex) 
                {
                    response = (HttpWebResponse)ex.Response; 
                    if (null == response)
                    {
                        throw;
                    } 
                }
 
                this.SetHttpWebResponse(Util.NullCheck(response, InternalError.InvalidGetResponse)); 

                if (HttpStatusCode.NoContent != this.StatusCode) 
                {
                    using (Stream stream = this.httpWebResponse.GetResponseStream())
                    {
                        if (null != stream) 
                        {
                            Stream copy = this.GetAsyncResponseStreamCopy(); 
                            this.responseStream = copy; 

                            Byte[] buffer = this.GetAsyncResponseStreamCopyBuffer(); 

                            long copied = WebUtil.CopyStream(stream, copy, ref buffer);
                            if (this.responseStreamOwner)
                            { 
                                if (0 == copied)
                                { 
                                    this.responseStream = null; 
                                }
                                else if (copy.Position < copy.Length) 
                                {   // In Silverlight, generally 3 bytes less than advertised by ContentLength are read
                                    ((MemoryStream)copy).SetLength(copy.Position);
                                }
                            } 

                            this.PutAsyncResponseStreamCopyBuffer(buffer); 
                        } 
                    }
                } 
            }
            catch (Exception e)
            {
                this.HandleFailure(e); 
                throw;
            } 
            finally 
            {
                this.SetCompleted(); 
                this.CompletedRequest();
            }

            if (null != this.Failure) 
            {
                throw this.Failure; 
            } 
        }
#endif 

        /// 
        /// Returns the response for the request.
        ///  
        /// materialized results for the request.
        /// element type of the results. 
        /// returns the instance of QueryOperationResponse containing the response. 
        internal QueryOperationResponse GetResponse(IEnumerable results, Type elementType)
        { 
            if (this.httpWebResponse != null)
            {
                Dictionary headers = WebUtil.WrapResponseHeaders(this.httpWebResponse);
                QueryOperationResponse response = QueryOperationResponse.GetInstance(elementType, headers, this.ServiceRequest, results); 
                response.StatusCode = (int)this.httpWebResponse.StatusCode;
                return response; 
            } 

            return null; 
        }

        /// cleanup work to do once the request has completed
        protected override void CompletedRequest() 
        {
            Util.Dispose(ref this.asyncResponseStream); 
            Util.Dispose(ref this.requestStream); 
            Util.Dispose(ref this.requestStreamContent);
 
            byte[] buffer = this.asyncStreamCopyBuffer;
            this.asyncStreamCopyBuffer = null;
#if StreamContainsBuffer
            if (!this.responseStreamIsCopyBuffer) 
#endif
            if ((null != buffer) && !this.usingBuffer) 
            { 
                this.PutAsyncResponseStreamCopyBuffer(buffer);
            } 

            if (this.responseStreamOwner)
            {
                if (null != this.responseStream) 
                {
                    this.responseStream.Position = 0; 
                } 
            }
 
            Debug.Assert(null != this.httpWebResponse || null != this.Failure, "should have response or exception");
            if (null != this.httpWebResponse)
            {
                // we've cached off what we need, headers still accessible after close 
                this.httpWebResponse.Close();
 
                Exception ex = DataServiceContext.HandleResponse(this.StatusCode, this.httpWebResponse.Headers[XmlConstants.HttpDataServiceVersion], this.GetResponseStream, false); 
                if (null != ex)
                { 
                    this.HandleFailure(ex);
                }
            }
        } 

        /// get stream which of copy buffer (via response stream) will be copied into 
        /// writtable stream, happens before GetAsyncResponseStreamCopyBuffer 
        protected virtual Stream GetAsyncResponseStreamCopy()
        { 
            this.responseStreamOwner = true;

            long length = this.contentLength;
            if ((0 < length) && (length <= Int32.MaxValue)) 
            {
                Debug.Assert(null == this.asyncStreamCopyBuffer, "not expecting buffer"); 
 
                byte[] buffer = new byte[(int)length];
#if StreamContainsBuffer 
                if (length < UInt16.MaxValue)
                {   // larger than this appears to cause trouble, specifically tested with 2619442
                    responseStreamIsCopyBuffer = true;
                    this.asyncStreamCopyBuffer = buffer; 
                }
#endif 
                return new MemoryStream(buffer, 0, buffer.Length, true, true); 
            }
 
            return new MemoryStream();
        }

        /// get buffer which response stream will be copied into 
        /// writtable stream
        protected virtual byte[] GetAsyncResponseStreamCopyBuffer() 
        {   // consider having a cache of these buffers since they will be pinned 
            Debug.Assert(null == this.asyncStreamCopyBuffer, "non-null this.asyncStreamCopyBuffer");
            return System.Threading.Interlocked.Exchange(ref reusableAsyncCopyBuffer, null) ?? new byte[8000]; 
        }

        /// returning a buffer after being done with it
        /// buffer to return 
        protected virtual void PutAsyncResponseStreamCopyBuffer(byte[] buffer)
        { 
            reusableAsyncCopyBuffer = buffer; 
        }
 
        /// set the http web response
        /// response object
        protected virtual void SetHttpWebResponse(HttpWebResponse response)
        { 
            this.httpWebResponse = response;
            this.statusCode = response.StatusCode; 
            this.contentLength = response.ContentLength; 
            this.contentType = response.ContentType;
        } 

        /// handle request.BeginGetRequestStream with request.EndGetRquestStream and then write out request stream
        /// async result
        [System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Design", "CA1031:DoNotCatchGeneralExceptionTypes", Justification = "required for this feature")] 
        private static void AsyncEndGetRequestStream(IAsyncResult asyncResult)
        { 
            QueryAsyncResult state = asyncResult.AsyncState as QueryAsyncResult; 
            try
            { 
                int step = CompleteCheck(state, InternalError.InvalidEndGetRequestCompleted);
                state.CompletedSynchronously &= asyncResult.CompletedSynchronously; // BeginGetRequestStream

                HttpWebRequest httpWebRequest = Util.NullCheck(state.Request, InternalError.InvalidEndGetRequestStreamRequest); 

                Stream stream = Util.NullCheck(httpWebRequest.EndGetRequestStream(asyncResult), InternalError.InvalidEndGetRequestStreamStream); 
                state.requestStream = stream; 

                MemoryStream memoryStream = Util.NullCheck(state.requestStreamContent, InternalError.InvalidEndGetRequestStreamContent); 
                byte[] buffer = memoryStream.GetBuffer();
                int bufferOffset = checked((int)memoryStream.Position);
                int bufferLength = checked((int)memoryStream.Length) - bufferOffset;
                if ((null == buffer) || (0 == bufferLength)) 
                {
                    Error.ThrowInternalError(InternalError.InvalidEndGetRequestStreamContentLength); 
                } 

                // the following is useful in the debugging Immediate Window 
                // string x = System.Text.Encoding.UTF8.GetString(buffer, bufferOffset, bufferLength);
                asyncResult = stream.BeginWrite(buffer, bufferOffset, bufferLength, QueryAsyncResult.AsyncEndWrite, state);

                bool reallyCompletedSynchronously = asyncResult.CompletedSynchronously && (step < state.asyncCompleteStep); 
                state.CompletedSynchronously &= reallyCompletedSynchronously; // BeginWrite
            } 
            catch (Exception e) 
            {
                if (state.HandleFailure(e)) 
                {
                    throw;
                }
            } 
            finally
            { 
                state.HandleCompleted(); 
            }
        } 

        /// handle reqestStream.BeginWrite with requestStream.EndWrite then BeginGetResponse
        /// async result
        [System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Design", "CA1031:DoNotCatchGeneralExceptionTypes", Justification = "required for this feature")] 
        private static void AsyncEndWrite(IAsyncResult asyncResult)
        { 
            QueryAsyncResult state = asyncResult.AsyncState as QueryAsyncResult; 
            try
            { 
                int step = CompleteCheck(state, InternalError.InvalidEndWriteCompleted);
                state.CompletedSynchronously &= asyncResult.CompletedSynchronously; // BeginWrite

                HttpWebRequest httpWebRequest = Util.NullCheck(state.Request, InternalError.InvalidEndWriteRequest); 

                Stream stream = Util.NullCheck(state.requestStream, InternalError.InvalidEndWriteStream); 
                stream.EndWrite(asyncResult); 

                state.requestStream = null; 
                stream.Dispose();

                stream = state.requestStreamContent;
                if (null != stream) 
                {
                    state.requestStreamContent = null; 
                    stream.Dispose(); 
                }
 
                asyncResult = httpWebRequest.BeginGetResponse(QueryAsyncResult.AsyncEndGetResponse, state);

                bool reallyCompletedSynchronously = asyncResult.CompletedSynchronously && (step < state.asyncCompleteStep);
                state.CompletedSynchronously &= reallyCompletedSynchronously; // BeginGetResponse 
            }
            catch (Exception e) 
            { 
                if (state.HandleFailure(e))
                { 
                    throw;
                }
            }
            finally 
            {
                state.HandleCompleted(); 
            } 
        }
 
        /// handle request.BeginGetResponse with request.EndGetResponse and then copy response stream
        /// async result
        [System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Design", "CA1031:DoNotCatchGeneralExceptionTypes", Justification = "required for this feature")]
        private static void AsyncEndGetResponse(IAsyncResult asyncResult) 
        {
            QueryAsyncResult state = asyncResult.AsyncState as QueryAsyncResult; 
            try 
            {
                int step = CompleteCheck(state, InternalError.InvalidEndGetResponseCompleted); 
                state.CompletedSynchronously &= asyncResult.CompletedSynchronously; // BeginGetResponse

                HttpWebRequest httpWebRequest = Util.NullCheck(state.Request, InternalError.InvalidEndGetResponseRequest);
 
                // the httpWebResponse is kept for batching, discarded by non-batch
                HttpWebResponse response = null; 
                try 
                {
                    response = (HttpWebResponse)httpWebRequest.EndGetResponse(asyncResult); 
                }
                catch (WebException e)
                {
                    response = (HttpWebResponse)e.Response; 
                    if (null == response)
                    { 
                        throw; 
                    }
                } 

                state.SetHttpWebResponse(Util.NullCheck(response, InternalError.InvalidEndGetResponseResponse));
                Debug.Assert(null == state.asyncResponseStream, "non-null asyncResponseStream");
 
                Stream stream = null;
                if (HttpStatusCode.NoContent != response.StatusCode) 
                { 
                    stream = response.GetResponseStream();
                    state.asyncResponseStream = stream; 
                }

                if ((null != stream) && stream.CanRead)
                { 
                    if (null == state.responseStream)
                    {   // this is the stream we copy the reponse to 
                        state.responseStream = Util.NullCheck(state.GetAsyncResponseStreamCopy(), InternalError.InvalidAsyncResponseStreamCopy); 
                    }
 
                    byte[] buffer = state.asyncStreamCopyBuffer;
                    if (null == state.asyncStreamCopyBuffer)
                    {   // this is the buffer we read into and copy out of
                        state.asyncStreamCopyBuffer = buffer = Util.NullCheck(state.GetAsyncResponseStreamCopyBuffer(), InternalError.InvalidAsyncResponseStreamCopyBuffer); 
                    }
 
                    bool reallyCompletedSynchronously = false; 
                    do
                    { 
                        int bufferOffset, bufferLength;
#if StreamContainsBuffer
                        if (state.responseStreamIsCopyBuffer)
                        {   // we may have asked for, but not received the entire stream 
                            bufferOffset = checked((int)state.responseStream.Position);
                            bufferLength = buffer.Length - bufferOffset; 
                        } 
                        else
#endif 
                        {
                            bufferOffset = 0;
                            bufferLength = buffer.Length;
                        } 

                        state.usingBuffer = true; 
                        asyncResult = stream.BeginRead(buffer, bufferOffset, bufferLength, QueryAsyncResult.AsyncEndRead, state); 

                        reallyCompletedSynchronously = asyncResult.CompletedSynchronously && (step < state.asyncCompleteStep); 
                        state.CompletedSynchronously &= reallyCompletedSynchronously; // BeginRead
                    }
                    while (reallyCompletedSynchronously && !state.IsCompletedInternally && stream.CanRead);
 
                    Debug.Assert(!reallyCompletedSynchronously || state.IsCompletedInternally, "AsyncEndGetResponse !IsCompleted");
                } 
                else 
                {
                    state.SetCompleted(); 
                }
            }
            catch (Exception e)
            { 
                if (state.HandleFailure(e))
                { 
                    throw; 
                }
            } 
            finally
            {
                state.HandleCompleted();
            } 
        }
 
        /// handle responseStream.BeginRead with responseStream.EndRead 
        /// async result
        [System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Design", "CA1031:DoNotCatchGeneralExceptionTypes", Justification = "required for this feature")] 
        private static void AsyncEndRead(IAsyncResult asyncResult)
        {
            QueryAsyncResult state = asyncResult.AsyncState as QueryAsyncResult;
            int count = 0; 
            try
            { 
                int step = CompleteCheck(state, InternalError.InvalidEndReadCompleted); 
                state.CompletedSynchronously &= asyncResult.CompletedSynchronously; // BeginRead
 
                Stream stream = Util.NullCheck(state.asyncResponseStream, InternalError.InvalidEndReadStream);
                Stream outputResponse = Util.NullCheck(state.responseStream, InternalError.InvalidEndReadCopy);
                byte[] buffer = Util.NullCheck(state.asyncStreamCopyBuffer, InternalError.InvalidEndReadBuffer);
                int bufferOffset = 0, bufferLength = 0; 

                count = stream.EndRead(asyncResult); 
                state.usingBuffer = false; 
                if (0 < count)
                { 
#if StreamContainsBuffer
                    if (state.responseStreamIsCopyBuffer)
                    {   // we may have asked for, but not received the entire stream
                        outputResponse.Position = outputResponse.Position + count; 
                        bufferOffset = checked((int)outputResponse.Position);
                        bufferLength = buffer.Length - bufferOffset; 
                    } 
                    else
#endif 
                    {
                        outputResponse.Write(buffer, 0, count);
                        bufferOffset = 0;
                        bufferLength = buffer.Length; 
                    }
                } 
 
                if ((0 < bufferLength) && stream.CanRead)
                { 
                    if (!asyncResult.CompletedSynchronously)
                    {   // if CompletedSynchronously then caller will call and we reduce risk of stack overflow
                        bool reallyCompletedSynchronously = false;
                        do 
                        {
                            state.usingBuffer = true; 
                            asyncResult = stream.BeginRead(buffer, bufferOffset, bufferLength, QueryAsyncResult.AsyncEndRead, state); 

                            reallyCompletedSynchronously = asyncResult.CompletedSynchronously && (step < state.asyncCompleteStep); 
                            state.CompletedSynchronously &= reallyCompletedSynchronously; // BeginRead
                        }
                        while (reallyCompletedSynchronously && !state.IsCompletedInternally && stream.CanRead);
 
                        Debug.Assert(!reallyCompletedSynchronously || state.IsCompletedInternally, "AsyncEndRead !IsCompleted");
                    } 
                } 
                else
                { 
#if StreamContainsBuffer
                    Debug.Assert(!state.responseStreamIsCopyBuffer || (outputResponse.Position == outputResponse.Length), "didn't read expected count");
#endif
                    Debug.Assert(state.ContentLength < 0 || outputResponse.Length == state.ContentLength, "didn't read expected ContentLength"); 
                    if (outputResponse.Position < outputResponse.Length)
                    { 
                        // In Silverlight, generally 3 bytes less than advertised by ContentLength are read 
                        ((MemoryStream)outputResponse).SetLength(outputResponse.Position);
                    } 

                    state.SetCompleted();
                }
            } 
            catch (Exception e)
            { 
                if (state.HandleFailure(e)) 
                {
                    throw; 
                }
            }
            finally
            { 
                state.HandleCompleted();
            } 
        } 

        /// verify non-null and not completed 
        /// async result
        /// error code if null or completed
        /// the next step to validate CompletedSyncronously
        private static int CompleteCheck(QueryAsyncResult pereq, InternalError errorcode) 
        {
            if ((null == pereq) || pereq.IsCompletedInternally) 
            { 
                Error.ThrowInternalError(errorcode);
            } 

            return ++pereq.asyncCompleteStep;
        }
    } 
}

// File provided for Reference Use Only by Microsoft Corporation (c) 2007.
//---------------------------------------------------------------------- 
// 
//      Copyright (c) Microsoft Corporation.  All rights reserved.
// 
//  
// query object
//  
//--------------------------------------------------------------------- 

namespace System.Data.Services.Client 
{
    using System;
    using System.Collections;
    using System.Collections.Generic; 
    using System.Diagnostics;
    using System.IO; 
#if !ASTORIA_LIGHT // Data.Services http stack 
    using System.Net;
#else 
    using System.Data.Services.Http;
#endif

    ///  
    /// Wrapper HttpWebRequest & HttWebResponse
    ///  
    internal class QueryAsyncResult : BaseAsyncResult 
    {
        /// Originating service request 
        internal readonly DataServiceRequest ServiceRequest;

        /// Originating WebRequest
        internal readonly HttpWebRequest Request; 

        /// reusuable async copy buffer 
        private static byte[] reusableAsyncCopyBuffer; 

        /// content to write to request stream 
        private MemoryStream requestStreamContent;

        /// active web request stream
        private Stream requestStream; 

        /// web response, closed when completed 
        private HttpWebResponse httpWebResponse; 

        /// async response stream, closed when completed 
        private Stream asyncResponseStream;

        /// buffer when copying async stream to response stream cache
        private byte[] asyncStreamCopyBuffer; 

        /// response stream, returned to other parts of the system 
        /// with async, the asyncResponseStream is copied into this stream 
        private Stream responseStream;
 
        /// copy of HttpWebResponse.ContentType
        private string contentType;

        /// copy of HttpWebResponse.ContentLength 
        private long contentLength;
 
        /// copy of HttpWebResponse.StatusCode 
        private HttpStatusCode statusCode;
 
        /// 
        /// does this own the response stream or does the container of this QueryAsyncResult?
        /// 
        private bool responseStreamOwner; 

        ///  
        /// if the BeginRead has been called with asyncStreamCopyBuffer, but EndRead has not. 
        /// do not return the buffer to general pool if any question of it being in use.
        ///  
        private bool usingBuffer;

#if StreamContainsBuffer
        /// does the responseStream contain the asyncStreamCopyBuffer? 
        /// optimize reading in to the async buffer without copying into separate response stream
        private bool responseStreamIsCopyBuffer; 
#endif 

        /// If CompletedSynchronously and asyncCompleteStep didn't increment, then underlying implementation lied. 
        private int asyncCompleteStep;

        /// constructor
        /// source object of async request 
        /// async method name on source object
        /// Originating serviceRequest 
        /// Originating WebRequest 
        /// user callback
        /// user state 
        internal QueryAsyncResult(object source, string method, DataServiceRequest serviceRequest, HttpWebRequest request, AsyncCallback callback, object state)
            : base(source, method, callback, state)
        {
            Debug.Assert(null != request, "null request"); 
            this.ServiceRequest = serviceRequest;
            this.Request = request; 
        } 

        #region HttpResponse wrapper - ContentLength, ContentType, StatusCode 

        /// HttpWebResponse.ContentLength
        internal long ContentLength
        { 
            get { return this.contentLength; }
        } 
 
        /// HttpWebResponse.ContentType
        internal string ContentType 
        {
            get { return this.contentType; }
        }
 
        /// HttpWebResponse.StatusCode
        internal HttpStatusCode StatusCode 
        { 
            get { return this.statusCode; }
        } 

        #endregion

        ///  
        /// Ends the asynchronous query request.
        ///  
        /// Element type of the result. 
        /// Source object of async request.
        /// The asyncResult being ended. 
        /// Data service response.
        internal static QueryAsyncResult EndExecute(object source, IAsyncResult asyncResult)
        {
            QueryAsyncResult response = null; 

            try 
            { 
                response = BaseAsyncResult.EndExecute(source, "Execute", asyncResult);
            } 
            catch (InvalidOperationException ex)
            {
                response = asyncResult as QueryAsyncResult;
                Debug.Assert(response != null, "response != null, BaseAsyncResult.EndExecute() would have thrown a different exception otherwise."); 

                QueryOperationResponse operationResponse = response.GetResponse(null, typeof(TElement)); 
                if (operationResponse != null) 
                {
                    operationResponse.Error = ex; 
                    throw new DataServiceQueryException(Strings.DataServiceException_GeneralError, ex, operationResponse);
                }

                throw; 
            }
 
            return response; 
        }
 
        /// wrapper for HttpWebResponse.GetResponseStream
        /// stream
        internal Stream GetResponseStream()
        { 
            return this.responseStream;
        } 
 
        /// start the asynchronous request
        /// content stream to send asynchronously in the request 
        internal void BeginExecute(MemoryStream requestContent)
        {
            try
            { 
                int step = ++this.asyncCompleteStep;
 
                IAsyncResult asyncResult; 
                if ((null != requestContent) && (0 < requestContent.Length))
                { 
                    requestContent.Position = 0;
                    this.requestStreamContent = requestContent;
                    this.Request.ContentLength = requestContent.Length;
                    asyncResult = this.Request.BeginGetRequestStream(QueryAsyncResult.AsyncEndGetRequestStream, this); 
                }
                else 
                { 
                    asyncResult = this.Request.BeginGetResponse(QueryAsyncResult.AsyncEndGetResponse, this);
                } 

                this.CompletedSynchronously &= asyncResult.CompletedSynchronously && (step < this.asyncCompleteStep);
            }
            catch (Exception e) 
            {
                this.HandleFailure(e); 
                throw; 
            }
            finally 
            {
                this.HandleCompleted();
            }
 
            Debug.Assert(!this.CompletedSynchronously || this.IsCompleted, "if CompletedSynchronously then MUST IsCompleted");
        } 
 
#if !ASTORIA_LIGHT
        /// Synchronous web request 
        /// content stream to send in the request
        internal void Execute(MemoryStream requestContent)
        {
            try 
            {
                if ((null != requestContent) && (0 < requestContent.Length)) 
                { 
                    using (System.IO.Stream stream = Util.NullCheck(this.Request.GetRequestStream(), InternalError.InvalidGetRequestStream))
                    { 
                        byte[] buffer = requestContent.GetBuffer();
                        int bufferOffset = checked((int)requestContent.Position);
                        int bufferLength = checked((int)requestContent.Length) - bufferOffset;
 
                        // the following is useful in the debugging Immediate Window
                        // string x = System.Text.Encoding.UTF8.GetString(buffer, bufferOffset, bufferLength); 
                        stream.Write(buffer, bufferOffset, bufferLength); 
                    }
                } 

                HttpWebResponse response = null;
                try
                { 
                    response = (HttpWebResponse)this.Request.GetResponse();
                } 
                catch (WebException ex) 
                {
                    response = (HttpWebResponse)ex.Response; 
                    if (null == response)
                    {
                        throw;
                    } 
                }
 
                this.SetHttpWebResponse(Util.NullCheck(response, InternalError.InvalidGetResponse)); 

                if (HttpStatusCode.NoContent != this.StatusCode) 
                {
                    using (Stream stream = this.httpWebResponse.GetResponseStream())
                    {
                        if (null != stream) 
                        {
                            Stream copy = this.GetAsyncResponseStreamCopy(); 
                            this.responseStream = copy; 

                            Byte[] buffer = this.GetAsyncResponseStreamCopyBuffer(); 

                            long copied = WebUtil.CopyStream(stream, copy, ref buffer);
                            if (this.responseStreamOwner)
                            { 
                                if (0 == copied)
                                { 
                                    this.responseStream = null; 
                                }
                                else if (copy.Position < copy.Length) 
                                {   // In Silverlight, generally 3 bytes less than advertised by ContentLength are read
                                    ((MemoryStream)copy).SetLength(copy.Position);
                                }
                            } 

                            this.PutAsyncResponseStreamCopyBuffer(buffer); 
                        } 
                    }
                } 
            }
            catch (Exception e)
            {
                this.HandleFailure(e); 
                throw;
            } 
            finally 
            {
                this.SetCompleted(); 
                this.CompletedRequest();
            }

            if (null != this.Failure) 
            {
                throw this.Failure; 
            } 
        }
#endif 

        /// 
        /// Returns the response for the request.
        ///  
        /// materialized results for the request.
        /// element type of the results. 
        /// returns the instance of QueryOperationResponse containing the response. 
        internal QueryOperationResponse GetResponse(IEnumerable results, Type elementType)
        { 
            if (this.httpWebResponse != null)
            {
                Dictionary headers = WebUtil.WrapResponseHeaders(this.httpWebResponse);
                QueryOperationResponse response = QueryOperationResponse.GetInstance(elementType, headers, this.ServiceRequest, results); 
                response.StatusCode = (int)this.httpWebResponse.StatusCode;
                return response; 
            } 

            return null; 
        }

        /// cleanup work to do once the request has completed
        protected override void CompletedRequest() 
        {
            Util.Dispose(ref this.asyncResponseStream); 
            Util.Dispose(ref this.requestStream); 
            Util.Dispose(ref this.requestStreamContent);
 
            byte[] buffer = this.asyncStreamCopyBuffer;
            this.asyncStreamCopyBuffer = null;
#if StreamContainsBuffer
            if (!this.responseStreamIsCopyBuffer) 
#endif
            if ((null != buffer) && !this.usingBuffer) 
            { 
                this.PutAsyncResponseStreamCopyBuffer(buffer);
            } 

            if (this.responseStreamOwner)
            {
                if (null != this.responseStream) 
                {
                    this.responseStream.Position = 0; 
                } 
            }
 
            Debug.Assert(null != this.httpWebResponse || null != this.Failure, "should have response or exception");
            if (null != this.httpWebResponse)
            {
                // we've cached off what we need, headers still accessible after close 
                this.httpWebResponse.Close();
 
                Exception ex = DataServiceContext.HandleResponse(this.StatusCode, this.httpWebResponse.Headers[XmlConstants.HttpDataServiceVersion], this.GetResponseStream, false); 
                if (null != ex)
                { 
                    this.HandleFailure(ex);
                }
            }
        } 

        /// get stream which of copy buffer (via response stream) will be copied into 
        /// writtable stream, happens before GetAsyncResponseStreamCopyBuffer 
        protected virtual Stream GetAsyncResponseStreamCopy()
        { 
            this.responseStreamOwner = true;

            long length = this.contentLength;
            if ((0 < length) && (length <= Int32.MaxValue)) 
            {
                Debug.Assert(null == this.asyncStreamCopyBuffer, "not expecting buffer"); 
 
                byte[] buffer = new byte[(int)length];
#if StreamContainsBuffer 
                if (length < UInt16.MaxValue)
                {   // larger than this appears to cause trouble, specifically tested with 2619442
                    responseStreamIsCopyBuffer = true;
                    this.asyncStreamCopyBuffer = buffer; 
                }
#endif 
                return new MemoryStream(buffer, 0, buffer.Length, true, true); 
            }
 
            return new MemoryStream();
        }

        /// get buffer which response stream will be copied into 
        /// writtable stream
        protected virtual byte[] GetAsyncResponseStreamCopyBuffer() 
        {   // consider having a cache of these buffers since they will be pinned 
            Debug.Assert(null == this.asyncStreamCopyBuffer, "non-null this.asyncStreamCopyBuffer");
            return System.Threading.Interlocked.Exchange(ref reusableAsyncCopyBuffer, null) ?? new byte[8000]; 
        }

        /// returning a buffer after being done with it
        /// buffer to return 
        protected virtual void PutAsyncResponseStreamCopyBuffer(byte[] buffer)
        { 
            reusableAsyncCopyBuffer = buffer; 
        }
 
        /// set the http web response
        /// response object
        protected virtual void SetHttpWebResponse(HttpWebResponse response)
        { 
            this.httpWebResponse = response;
            this.statusCode = response.StatusCode; 
            this.contentLength = response.ContentLength; 
            this.contentType = response.ContentType;
        } 

        /// handle request.BeginGetRequestStream with request.EndGetRquestStream and then write out request stream
        /// async result
        [System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Design", "CA1031:DoNotCatchGeneralExceptionTypes", Justification = "required for this feature")] 
        private static void AsyncEndGetRequestStream(IAsyncResult asyncResult)
        { 
            QueryAsyncResult state = asyncResult.AsyncState as QueryAsyncResult; 
            try
            { 
                int step = CompleteCheck(state, InternalError.InvalidEndGetRequestCompleted);
                state.CompletedSynchronously &= asyncResult.CompletedSynchronously; // BeginGetRequestStream

                HttpWebRequest httpWebRequest = Util.NullCheck(state.Request, InternalError.InvalidEndGetRequestStreamRequest); 

                Stream stream = Util.NullCheck(httpWebRequest.EndGetRequestStream(asyncResult), InternalError.InvalidEndGetRequestStreamStream); 
                state.requestStream = stream; 

                MemoryStream memoryStream = Util.NullCheck(state.requestStreamContent, InternalError.InvalidEndGetRequestStreamContent); 
                byte[] buffer = memoryStream.GetBuffer();
                int bufferOffset = checked((int)memoryStream.Position);
                int bufferLength = checked((int)memoryStream.Length) - bufferOffset;
                if ((null == buffer) || (0 == bufferLength)) 
                {
                    Error.ThrowInternalError(InternalError.InvalidEndGetRequestStreamContentLength); 
                } 

                // the following is useful in the debugging Immediate Window 
                // string x = System.Text.Encoding.UTF8.GetString(buffer, bufferOffset, bufferLength);
                asyncResult = stream.BeginWrite(buffer, bufferOffset, bufferLength, QueryAsyncResult.AsyncEndWrite, state);

                bool reallyCompletedSynchronously = asyncResult.CompletedSynchronously && (step < state.asyncCompleteStep); 
                state.CompletedSynchronously &= reallyCompletedSynchronously; // BeginWrite
            } 
            catch (Exception e) 
            {
                if (state.HandleFailure(e)) 
                {
                    throw;
                }
            } 
            finally
            { 
                state.HandleCompleted(); 
            }
        } 

        /// handle reqestStream.BeginWrite with requestStream.EndWrite then BeginGetResponse
        /// async result
        [System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Design", "CA1031:DoNotCatchGeneralExceptionTypes", Justification = "required for this feature")] 
        private static void AsyncEndWrite(IAsyncResult asyncResult)
        { 
            QueryAsyncResult state = asyncResult.AsyncState as QueryAsyncResult; 
            try
            { 
                int step = CompleteCheck(state, InternalError.InvalidEndWriteCompleted);
                state.CompletedSynchronously &= asyncResult.CompletedSynchronously; // BeginWrite

                HttpWebRequest httpWebRequest = Util.NullCheck(state.Request, InternalError.InvalidEndWriteRequest); 

                Stream stream = Util.NullCheck(state.requestStream, InternalError.InvalidEndWriteStream); 
                stream.EndWrite(asyncResult); 

                state.requestStream = null; 
                stream.Dispose();

                stream = state.requestStreamContent;
                if (null != stream) 
                {
                    state.requestStreamContent = null; 
                    stream.Dispose(); 
                }
 
                asyncResult = httpWebRequest.BeginGetResponse(QueryAsyncResult.AsyncEndGetResponse, state);

                bool reallyCompletedSynchronously = asyncResult.CompletedSynchronously && (step < state.asyncCompleteStep);
                state.CompletedSynchronously &= reallyCompletedSynchronously; // BeginGetResponse 
            }
            catch (Exception e) 
            { 
                if (state.HandleFailure(e))
                { 
                    throw;
                }
            }
            finally 
            {
                state.HandleCompleted(); 
            } 
        }
 
        /// handle request.BeginGetResponse with request.EndGetResponse and then copy response stream
        /// async result
        [System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Design", "CA1031:DoNotCatchGeneralExceptionTypes", Justification = "required for this feature")]
        private static void AsyncEndGetResponse(IAsyncResult asyncResult) 
        {
            QueryAsyncResult state = asyncResult.AsyncState as QueryAsyncResult; 
            try 
            {
                int step = CompleteCheck(state, InternalError.InvalidEndGetResponseCompleted); 
                state.CompletedSynchronously &= asyncResult.CompletedSynchronously; // BeginGetResponse

                HttpWebRequest httpWebRequest = Util.NullCheck(state.Request, InternalError.InvalidEndGetResponseRequest);
 
                // the httpWebResponse is kept for batching, discarded by non-batch
                HttpWebResponse response = null; 
                try 
                {
                    response = (HttpWebResponse)httpWebRequest.EndGetResponse(asyncResult); 
                }
                catch (WebException e)
                {
                    response = (HttpWebResponse)e.Response; 
                    if (null == response)
                    { 
                        throw; 
                    }
                } 

                state.SetHttpWebResponse(Util.NullCheck(response, InternalError.InvalidEndGetResponseResponse));
                Debug.Assert(null == state.asyncResponseStream, "non-null asyncResponseStream");
 
                Stream stream = null;
                if (HttpStatusCode.NoContent != response.StatusCode) 
                { 
                    stream = response.GetResponseStream();
                    state.asyncResponseStream = stream; 
                }

                if ((null != stream) && stream.CanRead)
                { 
                    if (null == state.responseStream)
                    {   // this is the stream we copy the reponse to 
                        state.responseStream = Util.NullCheck(state.GetAsyncResponseStreamCopy(), InternalError.InvalidAsyncResponseStreamCopy); 
                    }
 
                    byte[] buffer = state.asyncStreamCopyBuffer;
                    if (null == state.asyncStreamCopyBuffer)
                    {   // this is the buffer we read into and copy out of
                        state.asyncStreamCopyBuffer = buffer = Util.NullCheck(state.GetAsyncResponseStreamCopyBuffer(), InternalError.InvalidAsyncResponseStreamCopyBuffer); 
                    }
 
                    bool reallyCompletedSynchronously = false; 
                    do
                    { 
                        int bufferOffset, bufferLength;
#if StreamContainsBuffer
                        if (state.responseStreamIsCopyBuffer)
                        {   // we may have asked for, but not received the entire stream 
                            bufferOffset = checked((int)state.responseStream.Position);
                            bufferLength = buffer.Length - bufferOffset; 
                        } 
                        else
#endif 
                        {
                            bufferOffset = 0;
                            bufferLength = buffer.Length;
                        } 

                        state.usingBuffer = true; 
                        asyncResult = stream.BeginRead(buffer, bufferOffset, bufferLength, QueryAsyncResult.AsyncEndRead, state); 

                        reallyCompletedSynchronously = asyncResult.CompletedSynchronously && (step < state.asyncCompleteStep); 
                        state.CompletedSynchronously &= reallyCompletedSynchronously; // BeginRead
                    }
                    while (reallyCompletedSynchronously && !state.IsCompletedInternally && stream.CanRead);
 
                    Debug.Assert(!reallyCompletedSynchronously || state.IsCompletedInternally, "AsyncEndGetResponse !IsCompleted");
                } 
                else 
                {
                    state.SetCompleted(); 
                }
            }
            catch (Exception e)
            { 
                if (state.HandleFailure(e))
                { 
                    throw; 
                }
            } 
            finally
            {
                state.HandleCompleted();
            } 
        }
 
        /// handle responseStream.BeginRead with responseStream.EndRead 
        /// async result
        [System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Design", "CA1031:DoNotCatchGeneralExceptionTypes", Justification = "required for this feature")] 
        private static void AsyncEndRead(IAsyncResult asyncResult)
        {
            QueryAsyncResult state = asyncResult.AsyncState as QueryAsyncResult;
            int count = 0; 
            try
            { 
                int step = CompleteCheck(state, InternalError.InvalidEndReadCompleted); 
                state.CompletedSynchronously &= asyncResult.CompletedSynchronously; // BeginRead
 
                Stream stream = Util.NullCheck(state.asyncResponseStream, InternalError.InvalidEndReadStream);
                Stream outputResponse = Util.NullCheck(state.responseStream, InternalError.InvalidEndReadCopy);
                byte[] buffer = Util.NullCheck(state.asyncStreamCopyBuffer, InternalError.InvalidEndReadBuffer);
                int bufferOffset = 0, bufferLength = 0; 

                count = stream.EndRead(asyncResult); 
                state.usingBuffer = false; 
                if (0 < count)
                { 
#if StreamContainsBuffer
                    if (state.responseStreamIsCopyBuffer)
                    {   // we may have asked for, but not received the entire stream
                        outputResponse.Position = outputResponse.Position + count; 
                        bufferOffset = checked((int)outputResponse.Position);
                        bufferLength = buffer.Length - bufferOffset; 
                    } 
                    else
#endif 
                    {
                        outputResponse.Write(buffer, 0, count);
                        bufferOffset = 0;
                        bufferLength = buffer.Length; 
                    }
                } 
 
                if ((0 < bufferLength) && stream.CanRead)
                { 
                    if (!asyncResult.CompletedSynchronously)
                    {   // if CompletedSynchronously then caller will call and we reduce risk of stack overflow
                        bool reallyCompletedSynchronously = false;
                        do 
                        {
                            state.usingBuffer = true; 
                            asyncResult = stream.BeginRead(buffer, bufferOffset, bufferLength, QueryAsyncResult.AsyncEndRead, state); 

                            reallyCompletedSynchronously = asyncResult.CompletedSynchronously && (step < state.asyncCompleteStep); 
                            state.CompletedSynchronously &= reallyCompletedSynchronously; // BeginRead
                        }
                        while (reallyCompletedSynchronously && !state.IsCompletedInternally && stream.CanRead);
 
                        Debug.Assert(!reallyCompletedSynchronously || state.IsCompletedInternally, "AsyncEndRead !IsCompleted");
                    } 
                } 
                else
                { 
#if StreamContainsBuffer
                    Debug.Assert(!state.responseStreamIsCopyBuffer || (outputResponse.Position == outputResponse.Length), "didn't read expected count");
#endif
                    Debug.Assert(state.ContentLength < 0 || outputResponse.Length == state.ContentLength, "didn't read expected ContentLength"); 
                    if (outputResponse.Position < outputResponse.Length)
                    { 
                        // In Silverlight, generally 3 bytes less than advertised by ContentLength are read 
                        ((MemoryStream)outputResponse).SetLength(outputResponse.Position);
                    } 

                    state.SetCompleted();
                }
            } 
            catch (Exception e)
            { 
                if (state.HandleFailure(e)) 
                {
                    throw; 
                }
            }
            finally
            { 
                state.HandleCompleted();
            } 
        } 

        /// verify non-null and not completed 
        /// async result
        /// error code if null or completed
        /// the next step to validate CompletedSyncronously
        private static int CompleteCheck(QueryAsyncResult pereq, InternalError errorcode) 
        {
            if ((null == pereq) || pereq.IsCompletedInternally) 
            { 
                Error.ThrowInternalError(errorcode);
            } 

            return ++pereq.asyncCompleteStep;
        }
    } 
}

// File provided for Reference Use Only by Microsoft Corporation (c) 2007.

                        

Link Menu

Network programming in C#, Network Programming in VB.NET, Network Programming in .NET
This book is available now!
Buy at Amazon US or
Buy at Amazon UK