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); } }
protected virtual void CompleteCheck(PerRequest value, InternalError errorcode) { if ((value == null) || value.RequestCompleted) { Error.ThrowInternalError(errorcode); } }
/// <summary>Read and store response data for the current change, and try to start the next one</summary> /// <param name="pereq">the completed per request object</param> protected override void FinishCurrentChange(PerRequest pereq) { base.FinishCurrentChange(pereq); Debug.Assert(this.ResponseStream != null, "this.HttpWebResponseStream != null"); Debug.Assert((this.ResponseStream as MemoryStream) != null, "(this.HttpWebResponseStream as MemoryStream) != null"); if (this.ResponseStream.Position != 0) { // Set the stream to the start position and then parse the response and cache it this.ResponseStream.Position = 0; this.HandleOperationResponseData(this.responseMessage, this.ResponseStream); } else { this.HandleOperationResponseData(this.responseMessage, null); } pereq.Dispose(); this.perRequest = null; if (!pereq.RequestCompletedSynchronously) { // you can't chain synchronously completed responses without risking StackOverflow, caller will loop to next if (!this.IsCompletedInternally) { this.BeginCreateNextChange(); } } }
/// <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"); }
protected static void EqualRefCheck(PerRequest actual, PerRequest expected, InternalError errorcode) { if (!object.ReferenceEquals(actual, expected)) { Error.ThrowInternalError(errorcode); } }
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); } }
/// <summary>verify non-null and not completed</summary> /// <param name="pereq">async result</param> /// <param name="errorcode">error code if null or completed</param> protected override void CompleteCheck(PerRequest pereq, InternalError errorcode) { if ((null == pereq) || ((pereq.RequestCompleted || this.IsCompletedInternally) && !(this.IsAborted || pereq.RequestAborted))) { // if aborting, let the request throw its abort code Error.ThrowInternalError(errorcode); } }
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); } }
/// <summary>Read and store response data for the current change</summary> /// <param name="pereq">The completed per request object</param> /// <remarks>This is called only from the async code paths, when the response to the batch has been read fully.</remarks> protected override void FinishCurrentChange(PerRequest pereq) { base.FinishCurrentChange(pereq); // This resets the position in the buffered response stream to the beginning // so that we can start reading the response. // In this case the ResponseStream is always a MemoryStream since we cache the async response. this.ResponseStream.Position = 0; this.perRequest = null; this.SetCompleted(); }
protected virtual void FinishCurrentChange(PerRequest pereq) { if (!pereq.RequestCompleted) { Error.ThrowInternalError(InternalError.SaveNextChangeIncomplete); } PerRequest perRequest = this.perRequest; if (perRequest != null) { EqualRefCheck(perRequest, pereq, InternalError.InvalidSaveNextChange); } }
protected bool HandleFailure(PerRequest pereq, Exception e) { if (pereq != null) { if (this.IsAborted) { pereq.SetAborted(); } else { pereq.SetComplete(); } } return(this.HandleFailure(e)); }
/// <summary>Disposes the request object if it is not null. Invokes the user callback</summary> /// <param name="pereq">the request object</param> protected override void HandleCompleted(PerRequest pereq) { if (null != pereq) { this.SetCompletedSynchronously(pereq.RequestCompletedSynchronously); if (pereq.RequestCompleted) { System.Threading.Interlocked.CompareExchange(ref this.perRequest, null, pereq); pereq.Dispose(); } } this.HandleCompleted(); }
private void HandlePerRequest(PerRequest perRequest) { if (!perRequest.HasName()) { _updater.Register(x => x.Register(RegistrationBuilder.ForType(perRequest.Implementation).As(perRequest.Service).InstancePerDependency().CreateRegistration())); } else if (!perRequest.HasService()) { _updater.Register(x => x.Register(RegistrationBuilder.ForType(perRequest.Implementation).As(typeof(object)).Named(perRequest.Name, typeof(object)).InstancePerDependency().CreateRegistration())); } else { _updater.Register(x => x.Register(RegistrationBuilder.ForType(perRequest.Implementation).As(perRequest.Service).Named(perRequest.Name, perRequest.Service).InstancePerDependency().CreateRegistration())); } }
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"); }
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); } }
/// <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"); }
protected abstract void HandleCompleted(PerRequest pereq);
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); } }
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"); }
public override void HandleSingleton(CompositionBatch batch, PerRequest perRequest) { batch.AddPart(new ProxyPart(perRequest, CreatePart(perRequest))); }
/// <summary>Set the AsyncWait and invoke the user callback.</summary> /// <param name="pereq">the request object</param> protected override void HandleCompleted(PerRequest pereq) { if (null != pereq) { this.SetCompletedSynchronously(pereq.RequestCompletedSynchronously); if (pereq.RequestCompleted) { Interlocked.CompareExchange(ref this.perRequest, null, pereq); if (this.IsBatchRequest) { // all competing thread must complete this before user callback is invoked Interlocked.CompareExchange(ref this.batchResponseMessage, pereq.ResponseMessage, null); pereq.ResponseMessage = null; } pereq.Dispose(); } } this.HandleCompleted(); }
/// <summary> /// constructor /// </summary> /// <param name="pereq">Perrequest class</param> internal AsyncReadState(PerRequest pereq) { this.Pereq = pereq; this.totalByteCopied = 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"); }
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"); }
public virtual void HandleSingleton(CompositionBatch batch, PerRequest perRequest) { batch.AddPart(new ComponentPart(perRequest, _useSetterInjection)); }