public void Init()
 {
     this.context = new DataServiceContext(new Uri("http://temp.org/"), ODataProtocolVersion.V4);
     this.responseInfo = new ResponseInfo(new RequestInfo(this.context), MergeOption.NoTracking);
     this.readingHelper = new ODataMessageReadingHelper(this.responseInfo);
     this.atomResponseMessage = new ODataResponseMessageSimulator();
     this.atomResponseMessage.SetHeader(XmlConstants.HttpContentType, "ApplIcAtIOn/AtOm");
     this.jsonResponseMessage = new ODataResponseMessageSimulator();
     this.jsonResponseMessage.SetHeader(XmlConstants.HttpContentType, "ApplIcAtIOn/jsOn");
 }
Example #2
0
        internal static MaterializeAtom Materialize(
            ResponseInfo responseInfo,
            QueryComponents queryComponents,
            ProjectionPlan plan,
            string contentType,
            IODataResponseMessage message,
            ODataPayloadKind expectedPayloadKind)
        {
            Debug.Assert(null != queryComponents, "querycomponents");
            Debug.Assert(null != message, "message");

            // If there is no content (For e.g. /Customers(1)/BestFriend is null), we need to return empty results.
            if (message.StatusCode == (int)HttpStatusCode.NoContent || String.IsNullOrEmpty(contentType))
            {
                return(MaterializeAtom.EmptyResults);
            }

            return(new MaterializeAtom(responseInfo, queryComponents, plan, message, expectedPayloadKind));
        }
Example #3
0
        /// <summary>cleanup work to do once the request has completed</summary>
        protected override void CompletedRequest()
        {
            byte[] buffer = this.asyncStreamCopyBuffer;
            this.asyncStreamCopyBuffer = null;

            if ((null != buffer) && !this.usingBuffer)
            {
                this.PutAsyncResponseStreamCopyBuffer(buffer);
            }

            if (this.responseStreamOwner)
            {
                if (null != this.outputResponseStream)
                {
                    this.outputResponseStream.Position = 0;
                }
            }

            Debug.Assert(null != this.responseMessage || null != this.Failure || this.IsAborted, "should have response or exception");
            if (null != this.responseMessage)
            {
                // we've cached off what we need, headers still accessible after close
                WebUtil.DisposeMessage(this.responseMessage);

                Version   responseVersion;
                Exception ex = SaveResult.HandleResponse(
                    this.RequestInfo,
                    this.StatusCode,
                    this.responseMessage.GetHeader(XmlConstants.HttpODataVersion),
                    this.GetResponseStream,
                    false,
                    out responseVersion);
                if (null != ex)
                {
                    this.HandleFailure(ex);
                }
                else
                {
                    this.responseInfo = this.CreateResponseInfo();
                }
            }
        }
Example #4
0
#pragma warning restore 649
#endif

        #endregion Private fields

        /// <summary>
        /// constructor
        /// </summary>
        /// <param name="responseInfo">originating context</param>
        /// <param name="queryComponents">Query components (projection, expected type)</param>
        /// <param name="plan">Projection plan (if compiled in an earlier query).</param>
        /// <param name="responseMessage">responseMessage</param>
        /// <param name="payloadKind">The kind of the payload to materialize.</param>
        internal MaterializeAtom(
            ResponseInfo responseInfo,
            QueryComponents queryComponents,
            ProjectionPlan plan,
            IODataResponseMessage responseMessage,
            ODataPayloadKind payloadKind)
        {
            Debug.Assert(queryComponents != null, "queryComponents != null");

            this.responseInfo            = responseInfo;
            this.elementType             = queryComponents.LastSegmentType;
            this.expectingPrimitiveValue = PrimitiveType.IsKnownNullableType(elementType);

            Debug.Assert(responseMessage != null, "Response message is null! Did you mean to use Materializer.ResultsWrapper/EmptyResults?");

            Type implementationType;
            Type materializerType = GetTypeForMaterializer(this.expectingPrimitiveValue, this.elementType, responseInfo.Model, out implementationType);

            this.materializer = ODataMaterializer.CreateMaterializerForMessage(responseMessage, responseInfo, materializerType, queryComponents, plan, payloadKind);
        }
 private void MaterializeTest(HttpStatusCode statusCode, ODataPayloadKind payloadKind)
 {
     var uri = new Uri("http://any");
     var context = new DataServiceContext();
     var requestInfo = new RequestInfo(context);
     var responseInfo = new ResponseInfo(requestInfo, MergeOption.OverwriteChanges);
     var queryComponents = new QueryComponents(uri, new Version(4, 0), typeof(Product), null, null);
     var responseMessage = new HttpWebResponseMessage(
         new HeaderCollection(),
         (int)statusCode,
         () => new MemoryStream());
     var materialize = DataServiceRequest.Materialize(
         responseInfo,
         queryComponents,
         null,
         "application/json",
         responseMessage,
         payloadKind);
     Assert.IsNull(materialize.Context);
     Assert.IsNull(materialize.Current);
     var enumerable = materialize.Cast<object>();
     Assert.AreEqual(0, enumerable.Count());
 }
Example #6
0
        /// <summary>
        /// Get the materializer to process the response.
        /// </summary>
        /// <param name="entityDescriptor">entity descriptor whose response is getting materialized.</param>
        /// <param name="responseInfo">information about the response to be materialized.</param>
        /// <returns>an instance of MaterializeAtom, that can be used to materialize the response.</returns>
        /// <remarks>
        /// This can only be called from inside the HandleBatchResponse or during enumeration of the responses.
        /// This is used when processing responses for update operations.
        /// </remarks>
        protected override MaterializeAtom GetMaterializer(EntityDescriptor entityDescriptor, ResponseInfo responseInfo)
        {
            // check if the batch stream is empty or not
            Debug.Assert(this.currentOperationResponse != null, "There must be an active operation response for this method to work correctly.");
            Debug.Assert(!this.currentOperationResponse.HasEmptyContent, "We should not get here if the response is empty.");

            // Since this is used for processing responses to update operations there are no projections to apply.
            QueryComponents queryComponents = new QueryComponents(
                /*uri*/ null,
                Util.ODataVersionEmpty,
                entityDescriptor.Entity.GetType(),
                /*projection*/ null,
                /*normalizerRewrites*/ null);

            return(new MaterializeAtom(
                       responseInfo,
                       queryComponents,
                       /*projectionPlan*/ null,
                       this.currentOperationResponse.CreateResponseMessage(),
                       ODataPayloadKind.Resource));
        }
Example #7
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);
            }
        }
        /// <summary>
        /// This method is for parsing CUD operation payloads which should contain
        /// 1 a single entry
        /// 2 An Error
        /// </summary>
        /// <param name="message">the message for the payload</param>
        /// <param name="responseInfo">The current ResponseInfo object</param>
        /// <param name="expectedType">The expected type</param>
        /// <returns>the MaterializerEntry that was read</returns>
        internal static MaterializerEntry ParseSingleEntityPayload(IODataResponseMessage message, ResponseInfo responseInfo, Type expectedType)
        {
            ODataPayloadKind messageType = ODataPayloadKind.Entry;
            using (ODataMessageReader messageReader = CreateODataMessageReader(message, responseInfo, ref messageType))
            {
                IEdmType edmType = responseInfo.TypeResolver.ResolveExpectedTypeForReading(expectedType);
                ODataReaderWrapper reader = ODataReaderWrapper.Create(messageReader, messageType, edmType, responseInfo.ResponsePipeline);

                FeedAndEntryMaterializerAdapter parser = new FeedAndEntryMaterializerAdapter(messageReader, reader, responseInfo.Model, responseInfo.MergeOption);

                ODataEntry entry = null;
                bool readFeed = false;
                while (parser.Read())
                {
                    readFeed |= parser.CurrentFeed != null;
                    if (parser.CurrentEntry != null)
                    {
                        if (entry != null)
                        {
                            throw new InvalidOperationException(DSClient.Strings.AtomParser_SingleEntry_MultipleFound);
                        }

                        entry = parser.CurrentEntry;
                    }
                }

                if (entry == null)
                {
                    if (readFeed)
                    {
                        throw new InvalidOperationException(DSClient.Strings.AtomParser_SingleEntry_NoneFound);
                    }
                    else
                    {
                        throw new InvalidOperationException(DSClient.Strings.AtomParser_SingleEntry_ExpectedFeedOrEntry);
                    }
                }

                return MaterializerEntry.GetEntry(entry);
            }
        }
Example #9
0
        protected static ODataMessageReader CreateODataMessageReader(IODataResponseMessage responseMessage, ResponseInfo responseInfo, ref ODataPayloadKind payloadKind)
        {
            ODataMessageReaderSettings settings = responseInfo.ReadHelper.CreateSettings();

            ODataMessageReader odataMessageReader = responseInfo.ReadHelper.CreateReader(responseMessage, settings);

            if (payloadKind == ODataPayloadKind.Unsupported)
            {
                var payloadKinds = odataMessageReader.DetectPayloadKind().ToList();

                if (payloadKinds.Count == 0)
                {
                    throw DSClient.Error.InvalidOperation(DSClient.Strings.AtomMaterializer_InvalidResponsePayload(XmlConstants.DataWebNamespace));
                }

                // Pick the first payload kind detected by ODataLib and use that to parse the exception.
                // The only exception being payload with entity reference link(s). If one of the payload kinds
                // is reference links, then we need to give preference to reference link payloads.
                ODataPayloadKindDetectionResult detectionResult = payloadKinds.FirstOrDefault(k => k.PayloadKind == ODataPayloadKind.EntityReferenceLink || k.PayloadKind == ODataPayloadKind.EntityReferenceLinks);

                if (detectionResult == null)
                {
                    detectionResult = payloadKinds.First();
                }

                // Astoria client only supports atom, jsonlight and raw value payloads.
#pragma warning disable 618
                if (detectionResult.Format != ODataFormat.Atom && detectionResult.Format != ODataFormat.Json && detectionResult.Format != ODataFormat.RawValue)
#pragma warning restore 618
                {
                    throw DSClient.Error.InvalidOperation(DSClient.Strings.AtomMaterializer_InvalidContentTypeEncountered(responseMessage.GetHeader(XmlConstants.HttpContentType)));
                }

                payloadKind = detectionResult.PayloadKind;
            }

            return odataMessageReader;
        }
 /// <summary>
 /// Initializes a new instance of the <see cref="ODataMessageReadingHelper"/> class.
 /// </summary>
 /// <param name="responseInfo">The response info.</param>
 internal ODataMessageReadingHelper(ResponseInfo responseInfo)
 {
     Debug.Assert(responseInfo != null, "responseInfo != null");
     this.responseInfo = responseInfo;
 }
Example #11
0
        /// <summary>
        /// Get the materializer to process the response.
        /// </summary>
        /// <param name="entityDescriptor">entity descriptor whose response is getting materialized.</param>
        /// <param name="responseInfo">information about the response to be materialized.</param>
        /// <returns>an instance of MaterializeAtom, that can be used to materialize the response.</returns>
        protected override MaterializeAtom GetMaterializer(EntityDescriptor entityDescriptor, ResponseInfo responseInfo)
        {
            Debug.Assert(this.cachedResponse.Exception == null && this.cachedResponse.MaterializerEntry != null, "this.cachedResponse.Exception == null && this.cachedResponse.Entry != null");
            ODataResource entry = this.cachedResponse.MaterializerEntry == null ? null : this.cachedResponse.MaterializerEntry.Entry;

            return(new MaterializeAtom(responseInfo, new[] { entry }, entityDescriptor.Entity.GetType(), this.cachedResponse.MaterializerEntry.Format));
        }
Example #12
0
        /// <summary>
        /// Get the materializer to process the response.
        /// </summary>
        /// <param name="entityDescriptor">entity descriptor whose response is getting materialized.</param>
        /// <param name="responseInfo">information about the response to be materialized.</param>
        /// <returns>an instance of MaterializeAtom, that can be used to materialize the response.</returns>
        /// <remarks>
        /// This can only be called from inside the HandleBatchResponse or during enumeration of the responses.
        /// This is used when processing responses for update operations.
        /// </remarks>
        protected override MaterializeAtom GetMaterializer(EntityDescriptor entityDescriptor, ResponseInfo responseInfo)
        {
            // check if the batch stream is empty or not
            Debug.Assert(this.currentOperationResponse != null, "There must be an active operation response for this method to work correctly.");
            Debug.Assert(!this.currentOperationResponse.HasEmptyContent, "We should not get here if the response is empty.");

            // Since this is used for processing responses to update operations there are no projections to apply.
            QueryComponents queryComponents = new QueryComponents(
                /*uri*/ null,
                Util.ODataVersionEmpty,
                entityDescriptor.Entity.GetType(),
                /*projection*/ null,
                /*normalizerRewrites*/ null);
            return new MaterializeAtom(
                responseInfo,
                queryComponents,
                /*projectionPlan*/ null,
                this.currentOperationResponse.CreateResponseMessage(),
                ODataPayloadKind.Entry);
        }
 /// <summary>
 /// Initializes a new instance of the <see cref="ODataMessageReadingHelper"/> class.
 /// </summary>
 /// <param name="responseInfo">The response info.</param>
 internal ODataMessageReadingHelper(ResponseInfo responseInfo)
 {
     Debug.Assert(responseInfo != null, "responseInfo != null");
     this.responseInfo = responseInfo;
 }
Example #14
0
        public static ODataMaterializer CreateMaterializerForMessage(
            IODataResponseMessage responseMessage,
            ResponseInfo responseInfo,
            Type materializerType,
            QueryComponents queryComponents,
            ProjectionPlan plan,
            ODataPayloadKind payloadKind)
        {
            ODataMessageReader messageReader = CreateODataMessageReader(responseMessage, responseInfo, ref payloadKind);

            ODataMaterializer result;
            IEdmType edmType = null;

            try
            {
                ODataMaterializerContext materializerContext = new ODataMaterializerContext(responseInfo);

                // Since in V1/V2, astoria client allowed Execute<object> and depended on the typeresolver or the wire type name
                // to get the clr type to materialize. Hence if we see the materializer type as object, we should set the edmtype
                // to null, since there is no expected type.
                if (materializerType != typeof(System.Object))
                {
                    edmType = responseInfo.TypeResolver.ResolveExpectedTypeForReading(materializerType);
                }

                if (payloadKind == ODataPayloadKind.Entry || payloadKind == ODataPayloadKind.Feed)
                {
                    // In V1/V2, we allowed System.Object type to be allowed to pass to ExecuteQuery.
                    // Hence we need to explicitly check for System.Object to allow this
                    if (edmType != null && edmType.TypeKind != EdmTypeKind.Entity)
                    {
                        throw DSClient.Error.InvalidOperation(DSClient.Strings.AtomMaterializer_InvalidNonEntityType(materializerType.FullName));
                    }

                    ODataReaderWrapper reader = ODataReaderWrapper.Create(messageReader, payloadKind, edmType, responseInfo.ResponsePipeline);
                    EntityTrackingAdapter entityTrackingAdapter = new EntityTrackingAdapter(responseInfo.EntityTracker, responseInfo.MergeOption, responseInfo.Model, responseInfo.Context);
                    LoadPropertyResponseInfo loadPropertyResponseInfo = responseInfo as LoadPropertyResponseInfo;

                    if (loadPropertyResponseInfo != null)
                    {
                        result = new ODataLoadNavigationPropertyMaterializer(
                            messageReader,
                            reader,
                            materializerContext,
                            entityTrackingAdapter,
                            queryComponents,
                            materializerType,
                            plan,
                            loadPropertyResponseInfo);
                    }
                    else
                    {
                        result = new ODataReaderEntityMaterializer(
                            messageReader,
                            reader,
                            materializerContext,
                            entityTrackingAdapter,
                            queryComponents,
                            materializerType,
                            plan);
                    }
                }
                else
                {
                    switch (payloadKind)
                    {
                        case ODataPayloadKind.Value:
                            result = new ODataValueMaterializer(messageReader, materializerContext, materializerType, queryComponents.SingleResult);
                            break;
                        case ODataPayloadKind.Collection:
                            result = new ODataCollectionMaterializer(messageReader, materializerContext, materializerType, queryComponents.SingleResult);
                            break;
                        case ODataPayloadKind.Property:
                        case ODataPayloadKind.IndividualProperty:
                            // Top level properties cannot be of entity type.
                            if (edmType != null && edmType.TypeKind == EdmTypeKind.Entity)
                            {
                                throw DSClient.Error.InvalidOperation(DSClient.Strings.AtomMaterializer_InvalidEntityType(materializerType.FullName));
                            }

                            result = new ODataPropertyMaterializer(messageReader, materializerContext, materializerType, queryComponents.SingleResult);
                            break;
                        case ODataPayloadKind.EntityReferenceLinks:
                        case ODataPayloadKind.EntityReferenceLink:
                            result = new ODataLinksMaterializer(messageReader, materializerContext, materializerType, queryComponents.SingleResult);
                            break;

                        case ODataPayloadKind.Error:
                            var odataError = messageReader.ReadError();
                            throw new ODataErrorException(odataError.Message, odataError);
                        default:
                            throw DSClient.Error.InvalidOperation(DSClient.Strings.AtomMaterializer_InvalidResponsePayload(XmlConstants.DataWebNamespace));
                    }
                }

                return result;
            }
            catch (Exception ex)
            {
                if (CommonUtil.IsCatchableExceptionType(ex))
                {
                    // Dispose the message reader in all error scenarios.
                    messageReader.Dispose();
                }

                throw;
            }
        }
Example #15
0
 /// <summary>
 /// Get the materializer to process the response.
 /// </summary>
 /// <param name="entityDescriptor">entity descriptor whose response is getting materialized.</param>
 /// <param name="responseInfo">information about the response to be materialized.</param>
 /// <returns>an instance of MaterializeAtom, that can be used to materialize the response.</returns>
 protected abstract MaterializeAtom GetMaterializer(EntityDescriptor entityDescriptor, ResponseInfo responseInfo);
Example #16
0
        /// <summary>
        /// Materialize the response payload.
        /// </summary>
        /// <param name="entityDescriptor">entity descriptor whose response is getting materialized.</param>
        /// <param name="responseInfo">information about the response to be materialized.</param>
        /// <param name="etag">etag value, if specified in the response header.</param>
        private void MaterializeResponse(EntityDescriptor entityDescriptor, ResponseInfo responseInfo, string etag)
        {
            using (MaterializeAtom materializer = this.GetMaterializer(entityDescriptor, responseInfo))
            {
                materializer.SetInsertingObject(entityDescriptor.Entity);

                object materializedEntity = null;
                foreach (object x in materializer)
                {
                    Debug.Assert(materializedEntity == null, "entity == null");
                    if (materializedEntity != null)
                    {
                        Error.ThrowInternalError(InternalError.MaterializerReturningMoreThanOneEntity);
                    }

                    materializedEntity = x;
                }

                Debug.Assert(null != entityDescriptor.GetLatestIdentity(), "updated inserted should always gain an identity");
                Debug.Assert(materializedEntity == entityDescriptor.Entity, "x == entityDescriptor.Entity, should have same object generated by response");
                Debug.Assert(EntityStates.Unchanged == entityDescriptor.State, "should have moved out of insert");
                Debug.Assert(this.RequestInfo.EntityTracker.TryGetEntityDescriptor(entityDescriptor.GetLatestIdentity()) != null, "should have identity tracked");

                // If there was no etag specified in the payload, then we need to set the etag from the header
                if (entityDescriptor.GetLatestETag() == null)
                {
                    entityDescriptor.ETag = etag;
                }
            }
        }
Example #17
0
 /// <summary>
 /// Get the materializer to process the response.
 /// </summary>
 /// <param name="entityDescriptor">entity descriptor whose response is getting materialized.</param>
 /// <param name="responseInfo">information about the response to be materialized.</param>
 /// <returns>an instance of MaterializeAtom, that can be used to materialize the response.</returns>
 protected override MaterializeAtom GetMaterializer(EntityDescriptor entityDescriptor, ResponseInfo responseInfo)
 {
     Debug.Assert(this.cachedResponse.Exception == null && this.cachedResponse.MaterializerEntry != null, "this.cachedResponse.Exception == null && this.cachedResponse.Entry != null");
     ODataEntry entry = this.cachedResponse.MaterializerEntry == null ? null : this.cachedResponse.MaterializerEntry.Entry;
     return new MaterializeAtom(responseInfo, new[] { entry }, entityDescriptor.Entity.GetType(), this.cachedResponse.MaterializerEntry.Format);
 }
Example #18
0
        /// <summary>
        /// Handle the response payload.
        /// </summary>
        /// <param name="responseMsg">httpwebresponse instance.</param>
        /// <param name="responseStream">stream containing the response payload.</param>
        private void HandleOperationResponseData(IODataResponseMessage responseMsg, Stream responseStream)
        {
            Debug.Assert(this.entryIndex >= 0 && this.entryIndex < this.ChangedEntries.Count, string.Format(System.Globalization.CultureInfo.InvariantCulture, "this.entryIndex = '{0}', this.ChangedEntries.Count() = '{1}'", this.entryIndex, this.ChangedEntries.Count));

            // Parse the response
            Descriptor        current = this.ChangedEntries[this.entryIndex];
            MaterializerEntry entry   = default(MaterializerEntry);
            Version           responseVersion;
            Exception         exception = BaseSaveResult.HandleResponse(this.RequestInfo, (HttpStatusCode)responseMsg.StatusCode, responseMsg.GetHeader(XmlConstants.HttpODataVersion), () => { return(responseStream); }, false /*throwOnFailure*/, out responseVersion);

            var headers = new HeaderCollection(responseMsg);

            if (responseStream != null && current.DescriptorKind == DescriptorKind.Entity && exception == null)
            {
                // Only process the response if the current resource is an entity and it's an insert or update scenario
                EntityDescriptor entityDescriptor = (EntityDescriptor)current;

                // We were ignoring the payload for non-insert and non-update scenarios. We need to keep doing that.
                if (entityDescriptor.State == EntityStates.Added || entityDescriptor.StreamState == EntityStates.Added ||
                    entityDescriptor.State == EntityStates.Modified || entityDescriptor.StreamState == EntityStates.Modified)
                {
                    try
                    {
                        ResponseInfo responseInfo           = this.CreateResponseInfo(entityDescriptor);
                        var          responseMessageWrapper = new HttpWebResponseMessage(
                            headers,
                            responseMsg.StatusCode,
                            () => responseStream);

                        entry = ODataReaderEntityMaterializer.ParseSingleEntityPayload(responseMessageWrapper, responseInfo, entityDescriptor.Entity.GetType());
                        entityDescriptor.TransientEntityDescriptor = entry.EntityDescriptor;
                    }
                    catch (Exception ex)
                    {
                        exception = ex;

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

            this.cachedResponses.Add(new CachedResponse(
                                         current,
                                         headers,
                                         (HttpStatusCode)responseMsg.StatusCode,
                                         responseVersion,
                                         entry,
                                         exception));

            if (exception != null)
            {
                current.SaveError = exception;

                // DEVNOTE(pqian):
                // There are two possible scenario here:
                // 1. We are in the sync code path, and there's an in stream error on the server side, or there are bad xml thrown
                // 2. We are in the async code path, there's a error thrown on the server side (any error)
                // Ideally, we need to check whether we want to continue to the next changeset. (Call this.CheckContinueOnError)
                // However, in V1/V2, we did not do this. Thus we will always continue on error on these scenarios
            }
        }