예제 #1
0
        private void AsyncEndWrite(IAsyncResult asyncResult)
        {
            AsyncStateBag asyncState = asyncResult.AsyncState as AsyncStateBag;
            PerRequest    request    = (asyncState == null) ? null : asyncState.PerRequest;

            try
            {
                this.CompleteCheck(request, InternalError.InvalidEndWriteCompleted);
                request.SetRequestCompletedSynchronously(asyncResult.CompletedSynchronously);
                EqualRefCheck(this.perRequest, request, InternalError.InvalidEndWrite);
                ContentStream requestContentStream = request.RequestContentStream;
                Util.NullCheck <ContentStream>(requestContentStream, InternalError.InvalidEndWriteStream);
                Util.NullCheck <Stream>(requestContentStream.Stream, InternalError.InvalidEndWriteStream);
                Util.NullCheck <Stream>(request.RequestStream, InternalError.InvalidEndWriteStream).EndWrite(asyncResult);
                if (!asyncResult.CompletedSynchronously)
                {
                    Stream stream = requestContentStream.Stream;
                    asyncResult = InvokeAsync(new AsyncAction(stream.BeginRead), request.RequestContentBuffer, 0, request.RequestContentBuffer.Length, new AsyncCallback(this.AsyncRequestContentEndRead), asyncState);
                    request.SetRequestCompletedSynchronously(asyncResult.CompletedSynchronously);
                }
            }
            catch (Exception exception)
            {
                if (this.HandleFailure(request, exception))
                {
                    throw;
                }
            }
            finally
            {
                this.HandleCompleted(request);
            }
        }
예제 #2
0
        private void AsyncRequestContentEndRead(IAsyncResult asyncResult)
        {
            AsyncStateBag asyncState = asyncResult.AsyncState as AsyncStateBag;
            PerRequest    request    = (asyncState == null) ? null : asyncState.PerRequest;

            try
            {
                this.CompleteCheck(request, InternalError.InvalidEndReadCompleted);
                request.SetRequestCompletedSynchronously(asyncResult.CompletedSynchronously);
                EqualRefCheck(this.perRequest, request, InternalError.InvalidEndRead);
                ContentStream requestContentStream = request.RequestContentStream;
                Util.NullCheck <ContentStream>(requestContentStream, InternalError.InvalidEndReadStream);
                Util.NullCheck <Stream>(requestContentStream.Stream, InternalError.InvalidEndReadStream);
                Stream stream2 = Util.NullCheck <Stream>(request.RequestStream, InternalError.InvalidEndReadStream);
                int    num     = requestContentStream.Stream.EndRead(asyncResult);
                if (0 < num)
                {
                    bool flag = request.RequestContentBufferValidLength == -1;
                    request.RequestContentBufferValidLength = num;
                    if (!asyncResult.CompletedSynchronously || flag)
                    {
                        do
                        {
                            asyncResult = InvokeAsync(new AsyncAction(stream2.BeginWrite), request.RequestContentBuffer, 0, request.RequestContentBufferValidLength, new AsyncCallback(this.AsyncEndWrite), asyncState);
                            request.SetRequestCompletedSynchronously(asyncResult.CompletedSynchronously);
                            if ((asyncResult.CompletedSynchronously && !request.RequestCompleted) && !this.IsCompletedInternally)
                            {
                                Stream stream = requestContentStream.Stream;
                                asyncResult = InvokeAsync(new AsyncAction(stream.BeginRead), request.RequestContentBuffer, 0, request.RequestContentBuffer.Length, new AsyncCallback(this.AsyncRequestContentEndRead), asyncState);
                                request.SetRequestCompletedSynchronously(asyncResult.CompletedSynchronously);
                            }
                        }while (((asyncResult.CompletedSynchronously && !request.RequestCompleted) && !this.IsCompletedInternally) && (request.RequestContentBufferValidLength > 0));
                    }
                }
                else
                {
                    request.RequestContentBufferValidLength = 0;
                    request.RequestStream = null;
                    stream2.Close();
                    ODataRequestMessageWrapper wrapper = Util.NullCheck <ODataRequestMessageWrapper>(request.Request, InternalError.InvalidEndWriteRequest);
                    asyncResult = InvokeAsync(new Func <ODataRequestMessageWrapper, AsyncCallback, object, IAsyncResult>(WebUtil.BeginGetResponse), wrapper, new AsyncCallback(this.AsyncEndGetResponse), asyncState);
                    request.SetRequestCompletedSynchronously(asyncResult.CompletedSynchronously);
                }
            }
            catch (Exception exception)
            {
                if (this.HandleFailure(request, exception))
                {
                    throw;
                }
            }
            finally
            {
                this.HandleCompleted(request);
            }
        }
예제 #3
0
        /// <summary>
        /// Make async calls to read the response stream.
        /// </summary>
        /// <param name="asyncStateBag">the state containing the information about the asynchronous operation.</param>
        private void ReadResponseStream(AsyncStateBag asyncStateBag)
        {
            Debug.Assert(asyncStateBag != null, "asyncStateBag != null");
            PerRequest   pereq       = asyncStateBag.PerRequest;
            IAsyncResult asyncResult = null;

            byte[] buffer             = this.asyncStreamCopyBuffer;
            Stream httpResponseStream = pereq.ResponseStream;

            do
            {
                int bufferOffset = 0;
                int bufferLength = buffer.Length;

                this.usingBuffer = true;
#if WINRT
                asyncResult = BaseAsyncResult.InvokeTask(httpResponseStream.ReadAsync, buffer, bufferOffset, bufferLength, this.AsyncEndRead, asyncStateBag);
#else
                asyncResult = BaseAsyncResult.InvokeAsync(httpResponseStream.BeginRead, buffer, bufferOffset, bufferLength, this.AsyncEndRead, asyncStateBag);
#endif
                pereq.SetRequestCompletedSynchronously(asyncResult.CompletedSynchronously);
                this.SetCompletedSynchronously(asyncResult.CompletedSynchronously); // BeginRead
            }while (asyncResult.CompletedSynchronously && !pereq.RequestCompleted && !this.IsCompletedInternally && httpResponseStream.CanRead);

            Debug.Assert((!this.CompletedSynchronously && !pereq.RequestCompletedSynchronously) || this.IsCompletedInternally || pereq.RequestCompleted, "AsyncEndGetResponse !IsCompleted");
        }
예제 #4
0
        private void AsyncEndRead(IAsyncResult asyncResult)
        {
            Debug.Assert(asyncResult != null && asyncResult.IsCompleted, "asyncResult.IsCompleted");
            AsyncStateBag asyncStateBag = asyncResult.AsyncState as AsyncStateBag;
            PerRequest    pereq         = asyncStateBag == null ? null : asyncStateBag.PerRequest;

            int count = 0;

            try
            {
                this.CompleteCheck(pereq, InternalError.InvalidEndReadCompleted);
                pereq.SetRequestCompletedSynchronously(asyncResult.CompletedSynchronously); // BeginRead
                this.SetCompletedSynchronously(asyncResult.CompletedSynchronously);

                Stream httpResponseStream = Util.NullCheck(pereq.ResponseStream, InternalError.InvalidEndReadStream); // get the http response stream.

                Stream outResponseStream = Util.NullCheck(this.outputResponseStream, InternalError.InvalidEndReadCopy);

                byte[] buffer = Util.NullCheck(this.asyncStreamCopyBuffer, InternalError.InvalidEndReadBuffer);
                count            = httpResponseStream.EndRead(asyncResult);
                this.usingBuffer = false;

                if (count > 0)
                {
                    outResponseStream.Write(buffer, 0, count);
                }

                if (count > 0 && buffer.Length > 0 && httpResponseStream.CanRead)
                {
                    if (!asyncResult.CompletedSynchronously)
                    {
                        // if CompletedSynchronously then caller will call and we reduce risk of stack overflow
                        this.ReadResponseStream(asyncStateBag);
                    }
                }
                else
                {
                    // Debug.Assert(this.ContentLength < 0 || outResponseStream.Length == this.ContentLength, "didn't read expected ContentLength");
                    if (outResponseStream.Position < outResponseStream.Length)
                    {
                        // In Silverlight, generally 3 bytes less than advertised by ContentLength are read
                        ((MemoryStream)outResponseStream).SetLength(outResponseStream.Position);
                    }

                    pereq.SetComplete();
                    this.SetCompleted();
                }
            }
            catch (Exception e)
            {
                if (this.HandleFailure(e))
                {
                    throw;
                }
            }
            finally
            {
                this.HandleCompleted(pereq);
            }
        }
예제 #5
0
        protected void AsyncEndGetRequestStream(IAsyncResult asyncResult)
        {
            AsyncStateBag      asyncState = asyncResult.AsyncState as AsyncStateBag;
            PerRequest         request    = (asyncState == null) ? null : asyncState.PerRequest;
            DataServiceContext context    = (asyncState == null) ? null : asyncState.Context;

            try
            {
                this.CompleteCheck(request, InternalError.InvalidEndGetRequestCompleted);
                request.SetRequestCompletedSynchronously(asyncResult.CompletedSynchronously);
                EqualRefCheck(this.perRequest, request, InternalError.InvalidEndGetRequestStream);
                Stream stream = Util.NullCheck <Stream>(WebUtil.EndGetRequestStream(Util.NullCheck <ODataRequestMessageWrapper>(request.Request, InternalError.InvalidEndGetRequestStreamRequest), asyncResult, context), InternalError.InvalidEndGetRequestStreamStream);
                request.RequestStream = stream;
                ContentStream requestContentStream = request.RequestContentStream;
                Util.NullCheck <ContentStream>(requestContentStream, InternalError.InvalidEndGetRequestStreamContent);
                Util.NullCheck <Stream>(requestContentStream.Stream, InternalError.InvalidEndGetRequestStreamContent);
                if (requestContentStream.IsKnownMemoryStream)
                {
                    MemoryStream stream3  = requestContentStream.Stream as MemoryStream;
                    byte[]       buffer   = stream3.GetBuffer();
                    int          position = (int)stream3.Position;
                    int          num2     = ((int)stream3.Length) - position;
                    if ((buffer == null) || (num2 == 0))
                    {
                        Error.ThrowInternalError(InternalError.InvalidEndGetRequestStreamContentLength);
                    }
                }
                request.RequestContentBufferValidLength = -1;
                Stream stream1 = requestContentStream.Stream;
                asyncResult = InvokeAsync(new AsyncAction(stream1.BeginRead), request.RequestContentBuffer, 0, request.RequestContentBuffer.Length, new AsyncCallback(this.AsyncRequestContentEndRead), asyncState);
                request.SetRequestCompletedSynchronously(asyncResult.CompletedSynchronously);
            }
            catch (Exception exception)
            {
                if (this.HandleFailure(request, exception))
                {
                    throw;
                }
            }
            finally
            {
                this.HandleCompleted(request);
            }
        }
예제 #6
0
        internal void BeginExecuteQuery()
        {
            IAsyncResult asyncResult = null;

            PerRequest    pereq         = new PerRequest();
            AsyncStateBag asyncStateBag = new AsyncStateBag(pereq);

            pereq.Request = this.Request;

            this.perRequest = pereq;

            try
            {
                if (this.requestContentStream != null && this.requestContentStream.Stream != null)
                {
                    if (this.requestContentStream.IsKnownMemoryStream)
                    {
                        this.Request.SetContentLengthHeader();
                    }

                    this.perRequest.RequestContentStream = this.requestContentStream;
                    asyncResult = BaseAsyncResult.InvokeAsync(this.Request.BeginGetRequestStream, this.AsyncEndGetRequestStream, asyncStateBag);
                }
                else
                {
                    asyncResult = BaseAsyncResult.InvokeAsync(this.Request.BeginGetResponse, this.AsyncEndGetResponse, asyncStateBag);
                }

                // TODO: 298920: Async execute methods for query (QueryResult.cs), should not need to maintain "CompletedSynchronously" information in two state variables.
                pereq.SetRequestCompletedSynchronously(asyncResult.CompletedSynchronously);
                this.SetCompletedSynchronously(asyncResult.CompletedSynchronously);
            }
            catch (Exception e)
            {
                this.HandleFailure(e);
                throw;
            }
            finally
            {
                this.HandleCompleted(pereq);
            }

            Debug.Assert((!this.CompletedSynchronously && !pereq.RequestCompletedSynchronously) || this.IsCompleted, "if CompletedSynchronously then MUST IsCompleted");
        }
예제 #7
0
        /// <summary>initial the async batch save changeset</summary>
        internal void BatchBeginRequest()
        {
            PerRequest pereq = null;

            try
            {
                ODataRequestMessageWrapper batchRequestMessage = this.GenerateBatchRequest();
                this.Abortable = batchRequestMessage;

                if (batchRequestMessage != null)
                {
                    batchRequestMessage.SetContentLengthHeader();
                    this.perRequest            = pereq = new PerRequest();
                    pereq.Request              = batchRequestMessage;
                    pereq.RequestContentStream = batchRequestMessage.CachedRequestStream;

                    AsyncStateBag asyncStateBag = new AsyncStateBag(pereq);

                    this.responseStream = new MemoryStream();
                    IAsyncResult asyncResult = BaseAsyncResult.InvokeAsync(batchRequestMessage.BeginGetRequestStream, this.AsyncEndGetRequestStream, asyncStateBag);
                    pereq.SetRequestCompletedSynchronously(asyncResult.CompletedSynchronously);
                }
                else
                {
                    Debug.Assert(this.CompletedSynchronously, "completedSynchronously");
                    Debug.Assert(this.IsCompletedInternally, "completed");
                }
            }
            catch (Exception e)
            {
                this.HandleFailure(pereq, e);
                throw; // to user on BeginSaveChangeSet, will still invoke Callback
            }
            finally
            {
                this.HandleCompleted(pereq); // will invoke user callback
            }

            Debug.Assert((this.CompletedSynchronously && this.IsCompleted) || !this.CompletedSynchronously, "sync without complete");
        }
예제 #8
0
        protected override void AsyncEndGetResponse(IAsyncResult asyncResult)
        {
            Debug.Assert(asyncResult != null && asyncResult.IsCompleted, "asyncResult.IsCompleted");
            AsyncStateBag asyncStateBag = asyncResult.AsyncState as AsyncStateBag;

            PerRequest pereq = asyncStateBag == null ? null : asyncStateBag.PerRequest;

            try
            {
                if (this.IsAborted)
                {
                    if (pereq != null)
                    {
                        pereq.SetComplete();
                    }

                    this.SetCompleted();
                }
                else
                {
                    this.CompleteCheck(pereq, InternalError.InvalidEndGetResponseCompleted);
                    pereq.SetRequestCompletedSynchronously(asyncResult.CompletedSynchronously);
                    this.SetCompletedSynchronously(asyncResult.CompletedSynchronously);

                    ODataRequestMessageWrapper requestMessage = Util.NullCheck(pereq.Request, InternalError.InvalidEndGetResponseRequest);

                    // the httpWebResponse is kept for batching, discarded by non-batch
                    IODataResponseMessage response = this.RequestInfo.EndGetResponse(requestMessage, asyncResult);
                    pereq.ResponseMessage = Util.NullCheck(response, InternalError.InvalidEndGetResponseResponse);

                    this.SetHttpWebResponse(pereq.ResponseMessage);

                    Debug.Assert(null == pereq.ResponseStream, "non-null async ResponseStream");
                    Stream httpResponseStream = null;

                    if (HttpStatusCode.NoContent != (HttpStatusCode)response.StatusCode)
                    {
                        httpResponseStream   = response.GetStream();
                        pereq.ResponseStream = httpResponseStream;
                    }

                    if ((null != httpResponseStream) && httpResponseStream.CanRead)
                    {
                        if (null == this.outputResponseStream)
                        {
                            // this is the stream we copy the reponse to
                            this.outputResponseStream = Util.NullCheck(this.GetAsyncResponseStreamCopy(), InternalError.InvalidAsyncResponseStreamCopy);
                        }

                        if (null == this.asyncStreamCopyBuffer)
                        {
                            // this is the buffer we read into and copy out of
                            this.asyncStreamCopyBuffer = Util.NullCheck(this.GetAsyncResponseStreamCopyBuffer(), InternalError.InvalidAsyncResponseStreamCopyBuffer);
                        }

                        // Make async calls to read the response stream
                        this.ReadResponseStream(asyncStateBag);
                    }
                    else
                    {
                        pereq.SetComplete();
                        this.SetCompleted();
                    }
                }
            }
            catch (Exception e)
            {
                if (this.HandleFailure(e))
                {
                    throw;
                }
            }
            finally
            {
                this.HandleCompleted(pereq);
            }
        }
예제 #9
0
        internal void BatchBeginRequest()
        {
            PerRequest pereq = null;
            try
            {
                ODataRequestMessageWrapper batchRequestMessage = this.GenerateBatchRequest();
                this.Abortable = batchRequestMessage;

                if (batchRequestMessage != null)
                {
                    batchRequestMessage.SetContentLengthHeader();
                    this.perRequest = pereq = new PerRequest();
                    pereq.Request = batchRequestMessage;
                    pereq.RequestContentStream = batchRequestMessage.CachedRequestStream;

                    AsyncStateBag asyncStateBag = new AsyncStateBag(pereq);

                    this.responseStream = new MemoryStream();
                    IAsyncResult asyncResult = BaseAsyncResult.InvokeAsync(batchRequestMessage.BeginGetRequestStream, this.AsyncEndGetRequestStream, asyncStateBag);
                    pereq.SetRequestCompletedSynchronously(asyncResult.CompletedSynchronously);
                }
                else
                {
                    Debug.Assert(this.CompletedSynchronously, "completedSynchronously");
                    Debug.Assert(this.IsCompletedInternally, "completed");
                }
            }
            catch (Exception e)
            {
                this.HandleFailure(pereq, e);
                throw; // to user on BeginSaveChangeSet, will still invoke Callback
            }
            finally
            {
                this.HandleCompleted(pereq); // will invoke user callback
            }

            Debug.Assert((this.CompletedSynchronously && this.IsCompleted) || !this.CompletedSynchronously, "sync without complete");
        }
예제 #10
0
        internal void BeginCreateNextChange()
        {
            Debug.Assert(!this.IsCompletedInternally, "why being called if already completed?");

            // create the memory stream required to cache the responses as we read async from the underlying http web response
            this.inMemoryResponseStream = new MemoryStream();

            // SaveCallback can't chain synchronously completed responses, caller will loop the to next change
            PerRequest pereq = null;
            IAsyncResult asyncResult = null;
            do
            {
                IODataResponseMessage responseMsg = null;
                ODataRequestMessageWrapper requestMessage = null;
                try
                {
                    if (null != this.perRequest)
                    {
                        this.SetCompleted();
                        Error.ThrowInternalError(InternalError.InvalidBeginNextChange);
                    }

                    requestMessage = this.CreateNextRequest();

                    // Keeping the old behavior (V1/V2) where the abortable was set to null,
                    // if CreateNextRequest returned null.
                    if (requestMessage == null)
                    {
                        this.Abortable = null;
                    }

                    if ((null != requestMessage) || (this.entryIndex < this.ChangedEntries.Count))
                    {
                        if (this.ChangedEntries[this.entryIndex].ContentGeneratedForSave)
                        {
                            Debug.Assert(this.ChangedEntries[this.entryIndex] is LinkDescriptor, "only expected RelatedEnd to presave");
                            Debug.Assert(
                                this.ChangedEntries[this.entryIndex].State == EntityStates.Added ||
                                this.ChangedEntries[this.entryIndex].State == EntityStates.Modified,
                                "only expected added to presave");
                            continue;
                        }

                        this.Abortable = requestMessage;
                        ContentStream contentStream = this.CreateNonBatchChangeData(this.entryIndex, requestMessage);
                        this.perRequest = pereq = new PerRequest();
                        pereq.Request = requestMessage;

                        AsyncStateBag asyncStateBag = new AsyncStateBag(pereq);

                        if (null == contentStream || null == contentStream.Stream)
                        {
                            asyncResult = BaseAsyncResult.InvokeAsync(requestMessage.BeginGetResponse, this.AsyncEndGetResponse, asyncStateBag);
                        }
                        else
                        {
                            if (contentStream.IsKnownMemoryStream)
                            {
                                requestMessage.SetContentLengthHeader();
                            }

                            pereq.RequestContentStream = contentStream;
                            asyncResult = BaseAsyncResult.InvokeAsync(requestMessage.BeginGetRequestStream, this.AsyncEndGetRequestStream, asyncStateBag);
                        }

                        pereq.SetRequestCompletedSynchronously(asyncResult.CompletedSynchronously);
                        this.SetCompletedSynchronously(pereq.RequestCompletedSynchronously);
                    }
                    else
                    {
                        this.SetCompleted();

                        if (this.CompletedSynchronously)
                        {
                            this.HandleCompleted(pereq);
                        }
                    }
                }
                catch (InvalidOperationException e)
                {
                    e = WebUtil.GetHttpWebResponse(e, ref responseMsg);
                    this.HandleOperationException(e, responseMsg);
                    this.HandleCompleted(pereq);
                }
                finally
                {
                    WebUtil.DisposeMessage(responseMsg);
                }

                // If the current request is completed synchronously, we need to call FinishCurrentChange() to process the response payload.
                // FinishCurrentChange() will not call BeginCreateNextChange() when the request is synchronous.
                // If the current request is completed asynchronously, an async thread will call FinishCurrentChange() to process the response payload.
                // FinishCurrentchange() will then call BeginCreateNextChange() from the async thread and we need to exit this loop.
                // If requestMessage = this.CreateNextRequest() returns null, we would have called this.SetCompleted() above and this.IsCompletedInternally
                // would be true. This means we are done processing all changed entries and we should not call this.FinishCurrentChange().
                if (null != pereq && pereq.RequestCompleted && pereq.RequestCompletedSynchronously && !this.IsCompletedInternally)
                {
                    Debug.Assert(requestMessage != null, "httpWebRequest != null");
                    this.FinishCurrentChange(pereq);
                }

                // In the condition for the do-while loop we must test for pereq.RequestCompletedSynchronously and not asyncResult.CompletedSynchronously.
                // pereq.RequestCompletedSynchronously is true only if all async calls completed synchronously.  If we don't exit this loop when
                // pereq.RequestCompletedSynchronously is false, the current thread and an async thread will both re-enter BeginCreateNextChange()
                // and we will fail.  We can only process one request at a given time.
            }
            while (((null == pereq) || (pereq.RequestCompleted && pereq.RequestCompletedSynchronously)) && !this.IsCompletedInternally);
            Debug.Assert((this.CompletedSynchronously && this.IsCompleted) || !this.CompletedSynchronously, "sync without complete");
            Debug.Assert(this.entryIndex < this.ChangedEntries.Count || this.ChangedEntries.All(o => o.ContentGeneratedForSave), "didn't generate content for all entities/links");
        }
예제 #11
0
        internal void BeginCreateNextChange()
        {
            Debug.Assert(!this.IsCompletedInternally, "why being called if already completed?");

            // create the memory stream required to cache the responses as we read async from the underlying http web response
            this.inMemoryResponseStream = new MemoryStream();

            // SaveCallback can't chain synchronously completed responses, caller will loop the to next change
            PerRequest   pereq       = null;
            IAsyncResult asyncResult = null;

            do
            {
                IODataResponseMessage      responseMsg    = null;
                ODataRequestMessageWrapper requestMessage = null;
                try
                {
                    if (this.perRequest != null)
                    {
                        this.SetCompleted();
                        Error.ThrowInternalError(InternalError.InvalidBeginNextChange);
                    }

                    requestMessage = this.CreateNextRequest();

                    // Keeping the old behavior (V1/V2) where the abortable was set to null,
                    // if CreateNextRequest returned null.
                    if (requestMessage == null)
                    {
                        this.Abortable = null;
                    }

                    if ((requestMessage != null) || (this.entryIndex < this.ChangedEntries.Count))
                    {
                        if (this.ChangedEntries[this.entryIndex].ContentGeneratedForSave)
                        {
                            Debug.Assert(this.ChangedEntries[this.entryIndex] is LinkDescriptor, "only expected RelatedEnd to presave");
                            Debug.Assert(
                                this.ChangedEntries[this.entryIndex].State == EntityStates.Added ||
                                this.ChangedEntries[this.entryIndex].State == EntityStates.Modified,
                                "only expected added to presave");
                            continue;
                        }

                        this.Abortable = requestMessage;
                        ContentStream contentStream = this.CreateNonBatchChangeData(this.entryIndex, requestMessage);
                        this.perRequest = pereq = new PerRequest();
                        pereq.Request   = requestMessage;

                        AsyncStateBag asyncStateBag = new AsyncStateBag(pereq);

                        if (contentStream == null || contentStream.Stream == null)
                        {
                            asyncResult = BaseAsyncResult.InvokeAsync(requestMessage.BeginGetResponse, this.AsyncEndGetResponse, asyncStateBag);
                        }
                        else
                        {
                            if (contentStream.IsKnownMemoryStream)
                            {
                                requestMessage.SetContentLengthHeader();
                            }

                            pereq.RequestContentStream = contentStream;
                            asyncResult = BaseAsyncResult.InvokeAsync(requestMessage.BeginGetRequestStream, this.AsyncEndGetRequestStream, asyncStateBag);
                        }

                        pereq.SetRequestCompletedSynchronously(asyncResult.CompletedSynchronously);
                        this.SetCompletedSynchronously(pereq.RequestCompletedSynchronously);
                    }
                    else
                    {
                        this.SetCompleted();

                        if (this.CompletedSynchronously)
                        {
                            this.HandleCompleted(pereq);
                        }
                    }
                }
                catch (InvalidOperationException e)
                {
                    e = WebUtil.GetHttpWebResponse(e, ref responseMsg);
                    this.HandleOperationException(e, responseMsg);
                    this.HandleCompleted(pereq);
                }
                finally
                {
                    WebUtil.DisposeMessage(responseMsg);
                }

                // If the current request is completed synchronously, we need to call FinishCurrentChange() to process the response payload.
                // FinishCurrentChange() will not call BeginCreateNextChange() when the request is synchronous.
                // If the current request is completed asynchronously, an async thread will call FinishCurrentChange() to process the response payload.
                // FinishCurrentchange() will then call BeginCreateNextChange() from the async thread and we need to exit this loop.
                // If requestMessage = this.CreateNextRequest() returns null, we would have called this.SetCompleted() above and this.IsCompletedInternally
                // would be true. This means we are done processing all changed entries and we should not call this.FinishCurrentChange().
                if (pereq != null && pereq.RequestCompleted && pereq.RequestCompletedSynchronously && !this.IsCompletedInternally)
                {
                    Debug.Assert(requestMessage != null, "httpWebRequest != null");
                    this.FinishCurrentChange(pereq);
                }

                // In the condition for the do-while loop we must test for pereq.RequestCompletedSynchronously and not asyncResult.CompletedSynchronously.
                // pereq.RequestCompletedSynchronously is true only if all async calls completed synchronously.  If we don't exit this loop when
                // pereq.RequestCompletedSynchronously is false, the current thread and an async thread will both re-enter BeginCreateNextChange()
                // and we will fail.  We can only process one request at a given time.
            }while (((pereq == null) || (pereq.RequestCompleted && pereq.RequestCompletedSynchronously)) && !this.IsCompletedInternally);
            Debug.Assert((this.CompletedSynchronously && this.IsCompleted) || !this.CompletedSynchronously, "sync without complete");
            Debug.Assert(this.entryIndex < this.ChangedEntries.Count || this.ChangedEntries.All(o => o.ContentGeneratedForSave), "didn't generate content for all entities/links");
        }