private void VerifyChangeOperationResponse(ChangeOperationResponseData expected, ChangeOperationResponse actual, int responseOrder)
        {
            this.Assert.IsNotNull(actual.Descriptor, GetVerificationFailureMessage(responseOrder, "Change operation response descriptor should not be null!"));
            this.VerifyDescriptor(expected.DescriptorData, actual.Descriptor, responseOrder);

            this.Assert.AreEqual(
                expected.StatusCode,
                actual.StatusCode,
                GetVerificationFailureMessage(responseOrder, "Status code verification failed for the change operation response data: {0}.", expected));

            // No headers verification

            // Verify exceptions
            if (!string.IsNullOrEmpty(expected.ExceptionId))
            {
                throw new TaupoNotSupportedException(
                    string.Format(
                    CultureInfo.InvariantCulture,
                    "Change operation response data with order {0} has non-null exception id '{1}'. This verifier does not support exception verification.",
                    responseOrder,
                    expected.ExceptionId));
            }

            this.Assert.IsNull(actual.Error, GetVerificationFailureMessage(responseOrder, "Unexpected exception thrown:\r\n{0}", actual.Error));

            this.Assert.AreEqual(
                expected.DescriptorData.State.ToProductEnum(),
                actual.Descriptor.State,
                GetVerificationFailureMessage(responseOrder, "Descriptor State verification failed for the change operation response data: {0}.", expected));
        }
Ejemplo n.º 2
0
        /// <summary>
        /// Handle the response.
        /// </summary>
        /// <returns>an instance of the DataServiceResponse, containing individual responses for all the requests made during this SaveChanges call.</returns>
        protected override DataServiceResponse HandleResponse()
        {
            List <OperationResponse> responses = new List <OperationResponse>(this.cachedResponses != null ? this.cachedResponses.Count : 0);
            DataServiceResponse      service   = new DataServiceResponse(null, -1, responses, false /*isBatch*/);
            Exception ex = null;

            try
            {
                foreach (CachedResponse response in this.cachedResponses)
                {
                    Descriptor descriptor = response.Descriptor;
                    this.SaveResultProcessed(descriptor);
                    OperationResponse operationResponse = new ChangeOperationResponse(response.Headers, descriptor);
                    operationResponse.StatusCode = (int)response.StatusCode;
                    if (response.Exception != null)
                    {
                        operationResponse.Error = response.Exception;

                        if (ex == null)
                        {
                            ex = response.Exception;
                        }
                    }
                    else
                    {
                        this.cachedResponse = response;
#if DEBUG
                        this.HandleOperationResponse(descriptor, response.Headers, response.StatusCode);
#else
                        this.HandleOperationResponse(descriptor, response.Headers);
#endif
                    }

                    responses.Add(operationResponse);
                }
            }
            catch (InvalidOperationException e)
            {
                ex = e;
            }

            if (ex != null)
            {
                throw new DataServiceRequestException(Strings.DataServiceException_GeneralError, ex, service);
            }

            return(service);
        }
Ejemplo n.º 3
0
        /// <summary>
        /// process the batch response
        /// </summary>
        /// <param name="batchReader">The batch reader to use for reading the batch response.</param>
        /// <returns>enumerable of QueryResponse or null</returns>
        /// <remarks>
        /// The batch message reader for the entire batch response is stored in this.batchMessageReader.
        /// Note that this method takes over the ownership of this reader and must Dispose it if it successfully returns.
        /// </remarks>
        private IEnumerable <OperationResponse> HandleBatchResponse(ODataBatchReader batchReader)
        {
            try
            {
                if (this.batchMessageReader == null)
                {
                    // The enumerable returned by this method can be enumerated multiple times.
                    // In that case it looks like if the method is called multiple times.
                    // This didn't fail in previous versions, it simply returned no results, so we need to do the same.
                    yield break;
                }

                Debug.Assert(batchReader != null, "batchReader != null");

                bool changesetFound  = false;
                bool insideChangeset = false;
                int  queryCount      = 0;
                int  operationCount  = 0;
                this.entryIndex = 0;
                while (batchReader.Read())
                {
                    switch (batchReader.State)
                    {
                        #region ChangesetStart
                    case ODataBatchReaderState.ChangesetStart:
                        if ((Util.IsBatchWithSingleChangeset(this.Options) && changesetFound) || (operationCount != 0))
                        {
                            // Throw if we encounter multiple changesets when running in batch with single changeset mode
                            // or if we encounter operations outside of a changeset.
                            Error.ThrowBatchUnexpectedContent(InternalError.UnexpectedBeginChangeSet);
                        }

                        insideChangeset = true;
                        break;
                        #endregion

                        #region ChangesetEnd
                    case ODataBatchReaderState.ChangesetEnd:
                        changesetFound  = true;
                        operationCount  = 0;
                        insideChangeset = false;
                        break;
                        #endregion

                        #region Operation
                    case ODataBatchReaderState.Operation:
                        Exception exception = this.ProcessCurrentOperationResponse(batchReader, insideChangeset);
                        if (!insideChangeset)
                        {
                            #region Get response
                            Debug.Assert(operationCount == 0, "missing an EndChangeSet 2");

                            QueryOperationResponse qresponse = null;
                            try
                            {
                                if (exception == null)
                                {
                                    DataServiceRequest query        = this.Queries[queryCount];
                                    ResponseInfo       responseInfo = this.RequestInfo.GetDeserializationInfo(null /*mergeOption*/);
                                    MaterializeAtom    materializer = DataServiceRequest.Materialize(
                                        responseInfo,
                                        query.QueryComponents(this.RequestInfo.Model),
                                        null,
                                        this.currentOperationResponse.Headers.GetHeader(XmlConstants.HttpContentType),
                                        this.currentOperationResponse.CreateResponseMessage(),
                                        query.PayloadKind);
                                    qresponse = QueryOperationResponse.GetInstance(query.ElementType, this.currentOperationResponse.Headers, query, materializer);
                                }
                            }
                            catch (ArgumentException e)
                            {
                                exception = e;
                            }
                            catch (FormatException e)
                            {
                                exception = e;
                            }
                            catch (InvalidOperationException e)
                            {
                                exception = e;
                            }

                            if (qresponse == null)
                            {
                                if (this.Queries != null)
                                {
                                    // this is the normal ExecuteBatch response
                                    DataServiceRequest query = this.Queries[queryCount];

                                    if (this.RequestInfo.IgnoreResourceNotFoundException && this.currentOperationResponse.StatusCode == HttpStatusCode.NotFound)
                                    {
                                        qresponse = QueryOperationResponse.GetInstance(query.ElementType, this.currentOperationResponse.Headers, query, MaterializeAtom.EmptyResults);
                                    }
                                    else
                                    {
                                        qresponse       = QueryOperationResponse.GetInstance(query.ElementType, this.currentOperationResponse.Headers, query, MaterializeAtom.EmptyResults);
                                        qresponse.Error = exception;
                                    }
                                }
                                else
                                {
                                    // This is top-level failure for SaveChanges(SaveChangesOptions.BatchWithSingleChangeset) or SaveChanges(SaveChangesOptions.BatchWithIndependentOperations) operations.
                                    // example: server doesn't support batching or number of batch objects exceeded an allowed limit.
                                    // ex could be null if the server responded to SaveChanges with an unexpected success with
                                    // response of batched GETS that did not correspond the original POST/PATCH/PUT/DELETE requests.
                                    // we expect non-null since server should have failed with a non-success code
                                    // and HandleResponse(status, ...) should generate the exception object
                                    throw exception;
                                }
                            }

                            qresponse.StatusCode = (int)this.currentOperationResponse.StatusCode;
                            queryCount++;
                            yield return(qresponse);

                            #endregion
                        }
                        else
                        {
                            #region Update response
                            try
                            {
                                Descriptor descriptor = this.ChangedEntries[this.entryIndex];
                                operationCount += this.SaveResultProcessed(descriptor);

                                if (exception != null)
                                {
                                    throw exception;
                                }

                                this.HandleOperationResponseHeaders(this.currentOperationResponse.StatusCode, this.currentOperationResponse.Headers);
#if DEBUG
                                this.HandleOperationResponse(descriptor, this.currentOperationResponse.Headers, this.currentOperationResponse.StatusCode);
#else
                                this.HandleOperationResponse(descriptor, this.currentOperationResponse.Headers);
#endif
                            }
                            catch (Exception e)
                            {
                                this.ChangedEntries[this.entryIndex].SaveError = e;
                                exception = e;

                                if (!CommonUtil.IsCatchableExceptionType(e))
                                {
                                    throw;
                                }
                            }

                            ChangeOperationResponse changeOperationResponse =
                                new ChangeOperationResponse(this.currentOperationResponse.Headers, this.ChangedEntries[this.entryIndex]);
                            changeOperationResponse.StatusCode = (int)this.currentOperationResponse.StatusCode;
                            if (exception != null)
                            {
                                changeOperationResponse.Error = exception;
                            }

                            operationCount++;
                            this.entryIndex++;
                            yield return(changeOperationResponse);

                            #endregion
                        }

                        break;
                        #endregion

                    default:
                        Error.ThrowBatchExpectedResponse(InternalError.UnexpectedBatchState);
                        break;
                    }
                }

                Debug.Assert(batchReader.State == ODataBatchReaderState.Completed, "unexpected batch state");

                // Check for a changeset without response (first line) or GET request without response (second line).
                // either all saved entries must be processed or it was a batch and one of the entries has the error
                if ((this.Queries == null &&
                     (!changesetFound ||
                      0 < queryCount ||
                      this.ChangedEntries.Any(o => o.ContentGeneratedForSave && o.SaveResultWasProcessed == 0) &&
                      (!this.IsBatchRequest || this.ChangedEntries.FirstOrDefault(o => o.SaveError != null) == null))) ||
                    (this.Queries != null && queryCount != this.Queries.Length))
                {
                    throw Error.InvalidOperation(Strings.Batch_IncompleteResponseCount);
                }
            }
            finally
            {
                // Note that this will be called only once the enumeration of all responses is finished and the Dispose
                // was called on the IEnumerator used for that enumeration. It is not called when the method returns,
                // since the compiler change this method to return the compiler-generated IEnumerable.
                Util.Dispose(ref this.batchMessageReader);
            }
        }
Ejemplo n.º 4
0
        /// <summary>
        /// process the batch response
        /// </summary>
        /// <param name="batchReader">The batch reader to use for reading the batch response.</param>
        /// <returns>enumerable of QueryResponse or null</returns>
        /// <remarks>
        /// The batch message reader for the entire batch response is stored in this.batchMessageReader.
        /// Note that this method takes over the ownership of this reader and must Dispose it if it successfully returns.
        /// </remarks>
        private IEnumerable<OperationResponse> HandleBatchResponse(ODataBatchReader batchReader)
        {
            try
            {
                if (this.batchMessageReader == null)
                {
                    // The enumerable returned by this method can be enumerated multiple times.
                    // In that case it looks like if the method is called multiple times.
                    // This didn't fail in previous versions, it simply returned no results, so we need to do the same.
                    yield break;
                }

                Debug.Assert(batchReader != null, "batchReader != null");

                bool changesetFound = false;
                bool insideChangeset = false;
                int queryCount = 0;
                int operationCount = 0;
                this.entryIndex = 0;
                while (batchReader.Read())
                {
                    switch (batchReader.State)
                    {
                        #region ChangesetStart
                        case ODataBatchReaderState.ChangesetStart:
                            if ((Util.IsBatchWithSingleChangeset(this.Options) && changesetFound) || (operationCount != 0))
                            {
                                // Throw if we encounter multiple changesets when running in batch with single changeset mode 
                                // or if we encounter operations outside of a changeset.
                                Error.ThrowBatchUnexpectedContent(InternalError.UnexpectedBeginChangeSet);
                            }

                            insideChangeset = true;
                            break;
                        #endregion

                        #region ChangesetEnd
                        case ODataBatchReaderState.ChangesetEnd:
                            changesetFound = true;
                            operationCount = 0;
                            insideChangeset = false;
                            break;
                        #endregion

                        #region Operation
                        case ODataBatchReaderState.Operation:
                            Exception exception = this.ProcessCurrentOperationResponse(batchReader, insideChangeset);
                            if (!insideChangeset)
                            {
                                #region Get response
                                Debug.Assert(operationCount == 0, "missing an EndChangeSet 2");

                                QueryOperationResponse qresponse = null;
                                try
                                {
                                    if (exception == null)
                                    {
                                        DataServiceRequest query = this.Queries[queryCount];
                                        ResponseInfo responseInfo = this.RequestInfo.GetDeserializationInfo(null /*mergeOption*/);
                                        MaterializeAtom materializer = DataServiceRequest.Materialize(
                                            responseInfo,
                                            query.QueryComponents(this.RequestInfo.Model),
                                            null,
                                            this.currentOperationResponse.Headers.GetHeader(XmlConstants.HttpContentType),
                                            this.currentOperationResponse.CreateResponseMessage(),
                                            query.PayloadKind);
                                        qresponse = QueryOperationResponse.GetInstance(query.ElementType, this.currentOperationResponse.Headers, query, materializer);
                                    }
                                }
                                catch (ArgumentException e)
                                {
                                    exception = e;
                                }
                                catch (FormatException e)
                                {
                                    exception = e;
                                }
                                catch (InvalidOperationException e)
                                {
                                    exception = e;
                                }

                                if (qresponse == null)
                                {
                                    if (this.Queries != null)
                                    {
                                        // this is the normal ExecuteBatch response
                                        DataServiceRequest query = this.Queries[queryCount];

                                        if (this.RequestInfo.IgnoreResourceNotFoundException && this.currentOperationResponse.StatusCode == HttpStatusCode.NotFound)
                                        {
                                            qresponse = QueryOperationResponse.GetInstance(query.ElementType, this.currentOperationResponse.Headers, query, MaterializeAtom.EmptyResults);
                                        }
                                        else
                                        {
                                            qresponse = QueryOperationResponse.GetInstance(query.ElementType, this.currentOperationResponse.Headers, query, MaterializeAtom.EmptyResults);
                                            qresponse.Error = exception;
                                        }
                                    }
                                    else
                                    {
                                        // This is top-level failure for SaveChanges(SaveChangesOptions.BatchWithSingleChangeset) or SaveChanges(SaveChangesOptions.BatchWithIndependentOperations) operations.
                                        // example: server doesn't support batching or number of batch objects exceeded an allowed limit.
                                        // ex could be null if the server responded to SaveChanges with an unexpected success with
                                        // response of batched GETS that did not correspond the original POST/PATCH/PUT/DELETE requests.
                                        // we expect non-null since server should have failed with a non-success code
                                        // and HandleResponse(status, ...) should generate the exception object
                                        throw exception;
                                    }
                                }

                                qresponse.StatusCode = (int)this.currentOperationResponse.StatusCode;
                                queryCount++;
                                yield return qresponse;
                                #endregion
                            }
                            else
                            {
                                #region Update response
                                try
                                {
                                    Descriptor descriptor = this.ChangedEntries[this.entryIndex];
                                    operationCount += this.SaveResultProcessed(descriptor);

                                    if (exception != null)
                                    {
                                        throw exception;
                                    }

                                    this.HandleOperationResponseHeaders(this.currentOperationResponse.StatusCode, this.currentOperationResponse.Headers);
#if DEBUG
                                    this.HandleOperationResponse(descriptor, this.currentOperationResponse.Headers, this.currentOperationResponse.StatusCode);
#else
                                    this.HandleOperationResponse(descriptor, this.currentOperationResponse.Headers);
#endif
                                }
                                catch (Exception e)
                                {
                                    this.ChangedEntries[this.entryIndex].SaveError = e;
                                    exception = e;

                                    if (!CommonUtil.IsCatchableExceptionType(e))
                                    {
                                        throw;
                                    }
                                }

                                ChangeOperationResponse changeOperationResponse =
                                    new ChangeOperationResponse(this.currentOperationResponse.Headers, this.ChangedEntries[this.entryIndex]);
                                changeOperationResponse.StatusCode = (int)this.currentOperationResponse.StatusCode;
                                if (exception != null)
                                {
                                    changeOperationResponse.Error = exception;
                                }

                                operationCount++;
                                this.entryIndex++;
                                yield return changeOperationResponse;
                                #endregion
                            }

                            break;
                        #endregion

                        default:
                            Error.ThrowBatchExpectedResponse(InternalError.UnexpectedBatchState);
                            break;
                    }
                }

                Debug.Assert(batchReader.State == ODataBatchReaderState.Completed, "unexpected batch state");

                // Check for a changeset without response (first line) or GET request without response (second line).
                // either all saved entries must be processed or it was a batch and one of the entries has the error
                if ((this.Queries == null &&
                    (!changesetFound ||
                     0 < queryCount ||
                     this.ChangedEntries.Any(o => o.ContentGeneratedForSave && o.SaveResultWasProcessed == 0) &&
                     (!this.IsBatchRequest || this.ChangedEntries.FirstOrDefault(o => o.SaveError != null) == null))) ||
                    (this.Queries != null && queryCount != this.Queries.Length))
                {
                    throw Error.InvalidOperation(Strings.Batch_IncompleteResponseCount);
                }
            }
            finally
            {
                // Note that this will be called only once the enumeration of all responses is finished and the Dispose
                // was called on the IEnumerator used for that enumeration. It is not called when the method returns,
                // since the compiler change this method to return the compiler-generated IEnumerable.
                Util.Dispose(ref this.batchMessageReader);
            }
        }
Ejemplo n.º 5
0
        /// <summary>
        /// Handle the response.
        /// </summary>
        /// <returns>an instance of the DataServiceResponse, containing individual responses for all the requests made during this SaveChanges call.</returns>
        protected override DataServiceResponse HandleResponse()
        {
            List<OperationResponse> responses = new List<OperationResponse>(this.cachedResponses != null ? this.cachedResponses.Count : 0);
            DataServiceResponse service = new DataServiceResponse(null, -1, responses, false /*isBatch*/);
            Exception ex = null;

            try
            {
                foreach (CachedResponse response in this.cachedResponses)
                {
                    Descriptor descriptor = response.Descriptor;
                    this.SaveResultProcessed(descriptor);
                    OperationResponse operationResponse = new ChangeOperationResponse(response.Headers, descriptor);
                    operationResponse.StatusCode = (int)response.StatusCode;
                    if (response.Exception != null)
                    {
                        operationResponse.Error = response.Exception;

                        if (ex == null)
                        {
                            ex = response.Exception;
                        }
                    }
                    else
                    {
                        this.cachedResponse = response;
#if DEBUG
                        this.HandleOperationResponse(descriptor, response.Headers, response.StatusCode);
#else
                        this.HandleOperationResponse(descriptor, response.Headers);
#endif
                    }

                    responses.Add(operationResponse);
                }
            }
            catch (InvalidOperationException e)
            {
                ex = e;
            }

            if (ex != null)
            {
                throw new DataServiceRequestException(Strings.DataServiceException_GeneralError, ex, service);
            }

            return service;
        }
Ejemplo n.º 6
0
 public ChangesetResponseWrapper(ChangeOperationResponse cr)
     : base(cr)
 {
     this._ChangesetResponse = cr;
 }