Ejemplo n.º 1
0
        /// <summary>
        /// Handle operation response
        /// </summary>
        /// <param name="descriptor">descriptor whose response is getting processed.</param>
        /// <param name="contentHeaders">content headers as returned in the response.</param>
        protected void HandleOperationResponse(Descriptor descriptor, HeaderCollection contentHeaders)
#endif
        {
            EntityStates streamState = EntityStates.Unchanged;
            if (descriptor.DescriptorKind == DescriptorKind.Entity)
            {
                EntityDescriptor entityDescriptor = (EntityDescriptor)descriptor;
                streamState = entityDescriptor.StreamState;
#if DEBUG
                if (entityDescriptor.StreamState == EntityStates.Added)
                {
                    // We do not depend anywhere for the status code to be Created (201). Hence changing the assert from checking for a specific status code
                    // to just checking for success status code.
                    Debug.Assert(
                        WebUtil.SuccessStatusCode(statusCode) && entityDescriptor.State == EntityStates.Modified && entityDescriptor.IsMediaLinkEntry,
                        "WebUtil.SuccessStatusCode(statusCode) && descriptor.State == EntityStates.Modified && descriptor.IsMediaLinkEntry -- Processing Post MR");
                }
                else if (entityDescriptor.StreamState == EntityStates.Modified)
                {
                    // We do not depend anywhere for the status code to be Created (201). Hence changing the assert from checking for a specific status code
                    // to just checking for success status code.
                    Debug.Assert(
                        WebUtil.SuccessStatusCode(statusCode) && entityDescriptor.IsMediaLinkEntry,
                        "WebUtil.SuccessStatusCode(statusCode) && descriptor.IsMediaLinkEntry -- Processing Put MR");
                }

                // if the entity is added state or modified state with patch requests
                if (streamState == EntityStates.Added || descriptor.State == EntityStates.Added ||
                    (descriptor.State == EntityStates.Modified && !Util.IsFlagSet(this.Options, SaveChangesOptions.ReplaceOnUpdate)))
                {
                    string location;
                    string odataEntityId;
                    contentHeaders.TryGetHeader(XmlConstants.HttpResponseLocation, out location);
                    contentHeaders.TryGetHeader(XmlConstants.HttpODataEntityId, out odataEntityId);

                    Debug.Assert(location == null || location == entityDescriptor.GetLatestEditLink().AbsoluteUri, "edit link must already be set to location header");
                    Debug.Assert((location == null && odataEntityId == null) || (odataEntityId ?? location) == UriUtil.UriToString(entityDescriptor.GetLatestIdentity()), "Identity must already be set");
                }
#endif
            }

            if (streamState == EntityStates.Added || descriptor.State == EntityStates.Added)
            {
                this.HandleResponsePost(descriptor, contentHeaders);
            }
            else if (streamState == EntityStates.Modified || descriptor.State == EntityStates.Modified)
            {
                this.HandleResponsePut(descriptor, contentHeaders);
            }
            else if (descriptor.State == EntityStates.Deleted)
            {
                this.HandleResponseDelete(descriptor);
            }

            // else condition is not interesting here and we intentionally do nothing.
        }
Ejemplo n.º 2
0
        private void HandleResponsePut(Descriptor descriptor, HeaderCollection responseHeaders)
        {
            Debug.Assert(descriptor != null, "descriptor != null");
            if (descriptor.DescriptorKind == DescriptorKind.Entity)
            {
                string etag;
                responseHeaders.TryGetHeader(XmlConstants.HttpResponseETag, out etag);
                EntityDescriptor entityDescriptor = (EntityDescriptor)descriptor;

                // Only process the response if the resource is an entity resource and process update response is set to true
                if (this.ProcessResponsePayload)
                {
                    this.MaterializeResponse(entityDescriptor, this.CreateResponseInfo(entityDescriptor), etag);
                }
                else
                {
                    if (EntityStates.Modified != entityDescriptor.State && EntityStates.Modified != entityDescriptor.StreamState)
                    {
                        Error.ThrowBatchUnexpectedContent(InternalError.EntryNotModified);
                    }

                    // We MUST process the MR before the MLE since we always issue the requests in that order.
                    if (entityDescriptor.StreamState == EntityStates.Modified)
                    {
                        entityDescriptor.StreamETag = etag;
                        entityDescriptor.StreamState = EntityStates.Unchanged;
                    }
                    else
                    {
                        Debug.Assert(entityDescriptor.State == EntityStates.Modified, "descriptor.State == EntityStates.Modified");
                        entityDescriptor.ETag = etag;
                        entityDescriptor.State = EntityStates.Unchanged;
                        entityDescriptor.PropertiesToSerialize.Clear();
                    }
                }
            }
            else if (descriptor.DescriptorKind == DescriptorKind.Link)
            {
                if ((EntityStates.Added == descriptor.State) || (EntityStates.Modified == descriptor.State))
                {
                    descriptor.State = EntityStates.Unchanged;
                }
                else if (EntityStates.Detached != descriptor.State)
                {   // this link may have been previously detached by a detaching entity
                    Error.ThrowBatchUnexpectedContent(InternalError.LinkBadState);
                }
            }
            else
            {
                Debug.Assert(descriptor.DescriptorKind == DescriptorKind.NamedStream, "it must be named stream");
                Debug.Assert(descriptor.State == EntityStates.Modified, "named stream must only be in modified state");
                descriptor.State = EntityStates.Unchanged;

                StreamDescriptor streamDescriptor = (StreamDescriptor)descriptor;

                // The named stream has been updated, so the old ETag value is stale. Replace
                // it with the new value or clear it if no value was specified.
                string etag;
                responseHeaders.TryGetHeader(XmlConstants.HttpResponseETag, out etag);
                streamDescriptor.ETag = etag;
            }
        }
Ejemplo n.º 3
0
        /// <summary>operation with HttpWebResponse</summary>
        /// <param name="statusCode">status code of the response.</param>
        /// <param name="headers">response headers.</param>
        protected void HandleOperationResponseHeaders(HttpStatusCode statusCode, HeaderCollection headers)
        {
            Descriptor descriptor = this.ChangedEntries[this.entryIndex];

            // in the first pass, the http response is packaged into a batch response (which is then processed in second pass).
            // in this first pass, (all added entities and first call of modified media link entities) update their edit location
            // added entities - so entities that have not sent content yet w/ reference links can inline those reference links in their payload
            // media entities - because they can change edit location which is then necessary for second call that includes property content
            if (descriptor.DescriptorKind == DescriptorKind.Entity)
            {
                EntityDescriptor entityDescriptor = (EntityDescriptor)descriptor;
                Debug.Assert(this.streamRequestKind != StreamRequestKind.PostMediaResource || descriptor.State == EntityStates.Modified, "For the POST MR, the entity state must be modified");

                // For POST and PATCH scenarios
                if (descriptor.State == EntityStates.Added ||
                    this.streamRequestKind == StreamRequestKind.PostMediaResource ||
                    !Util.IsFlagSet(this.Options, SaveChangesOptions.ReplaceOnUpdate))
                {
                    if (WebUtil.SuccessStatusCode(statusCode))
                    {
                        string location;
                        string odataEntityId;
                        Uri editLink = null;
                        headers.TryGetHeader(XmlConstants.HttpResponseLocation, out location);
                        headers.TryGetHeader(XmlConstants.HttpODataEntityId, out odataEntityId);

                        if (location != null)
                        {
                            // Verify the location header is an absolute uri
                            editLink = WebUtil.ValidateLocationHeader(location);
                        }
                        else if (descriptor.State == EntityStates.Added ||
                                 this.streamRequestKind == StreamRequestKind.PostMediaResource)
                        {
                            // For POST scenarios, location header must be specified.
                            throw Error.NotSupported(Strings.Deserialize_NoLocationHeader);
                        }

                        // Verify the id value if present. Otherwise we should use the location header
                        // as identity. This was done to avoid breaking change, since in V1/V2, we used
                        // to do this.
                        Uri odataId = null;
                        if (odataEntityId != null)
                        {
                            odataId = WebUtil.ValidateIdentityValue(odataEntityId);
                            if (location == null)
                            {
                                throw Error.NotSupported(Strings.Context_BothLocationAndIdMustBeSpecified);
                            }
                        }
                        else
                        {
                            // we already verified that the location must be an absolute uri
                            odataId = UriUtil.CreateUri(location, UriKind.Absolute);
                        }

                        if (null != editLink)
                        {
                            this.RequestInfo.EntityTracker.AttachLocation(entityDescriptor.Entity, odataId, editLink);
                        }
                    }
                }

                if (this.streamRequestKind != StreamRequestKind.None)
                {
                    if (!WebUtil.SuccessStatusCode(statusCode))
                    {
                        // If the request failed and it was the MR request we should not try to send the PUT MLE after it
                        // for one we don't have the location to send it to (if it was POST MR)
                        if (this.streamRequestKind == StreamRequestKind.PostMediaResource)
                        {
                            // If this was the POST MR it means we tried to add the entity. Now its state is Modified but we need
                            //   to revert back to Added so that user can retry by calling SaveChanges again.
                            Debug.Assert(descriptor.State == EntityStates.Modified, "Entity state should be set to Modified once we've sent the POST MR");
                            descriptor.State = EntityStates.Added;
                        }

                        // Just reset the streamRequestKind flag - that means that we will not try to PUT the MLE and instead skip over
                        //   to the next change (if we are to ignore errors that is)
                        this.streamRequestKind = StreamRequestKind.None;

                        // And we also need to mark it such that we generated the save content (which we did before the POST request in fact)
                        // to workaround the fact that we use the same descriptor object to track two requests.
                        descriptor.ContentGeneratedForSave = true;
                    }
                    else if (this.streamRequestKind == StreamRequestKind.PostMediaResource)
                    {
                        // We just finished a POST MR request and the PUT MLE coming immediately after it will
                        // need the new etag value from the server to succeed.
                        string etag;
                        if (headers.TryGetHeader(XmlConstants.HttpResponseETag, out etag))
                        {
                            entityDescriptor.ETag = etag;
                        }

                        // else is not interesting and we intentionally do nothing.
                    }
                }
            }
        }
Ejemplo n.º 4
0
 /// <summary>Handle changeset response.</summary>
 /// <param name="descriptor">descriptor whose response is getting handled.</param>
 /// <param name="contentHeaders">response headers.</param>
 private void HandleResponsePost(Descriptor descriptor, HeaderCollection contentHeaders)
 {
     if (descriptor.DescriptorKind == DescriptorKind.Entity)
     {
         string etag;
         contentHeaders.TryGetHeader(XmlConstants.HttpResponseETag, out etag);
         this.HandleResponsePost((EntityDescriptor)descriptor, etag);
     }
     else
     {
         HandleResponsePost((LinkDescriptor)descriptor);
     }
 }