예제 #1
0
        /// <summary>
        /// Generate the batch request for all changes to save.
        /// </summary>
        /// <returns>Returns the instance of ODataRequestMessage containing all the headers and payload for the batch request.</returns>
        private ODataRequestMessageWrapper GenerateBatchRequest()
        {
            if (this.ChangedEntries.Count == 0 && this.Queries == null)
            {
                this.SetCompleted();
                return(null);
            }

            ODataRequestMessageWrapper batchRequestMessage = this.CreateBatchRequest();

            // we need to fire request after the headers have been written, but before we write the payload
            batchRequestMessage.FireSendingRequest2(null);

            using (ODataMessageWriter messageWriter = Serializer.CreateMessageWriter(batchRequestMessage, this.RequestInfo, false /*isParameterPayload*/))
            {
                this.batchWriter = messageWriter.CreateODataBatchWriter();
                this.batchWriter.WriteStartBatch();

                if (this.Queries != null)
                {
                    foreach (DataServiceRequest query in this.Queries)
                    {
                        QueryComponents queryComponents = query.QueryComponents(this.RequestInfo.Model);
                        Uri             requestUri      = this.RequestInfo.BaseUriResolver.GetOrCreateAbsoluteUri(queryComponents.Uri);

                        Debug.Assert(requestUri != null, "request uri is null");
                        Debug.Assert(requestUri.IsAbsoluteUri, "request uri is not absolute uri");

                        HeaderCollection headers = new HeaderCollection();

                        headers.SetRequestVersion(queryComponents.Version, this.RequestInfo.MaxProtocolVersionAsVersion);

                        this.RequestInfo.Format.SetRequestAcceptHeaderForQuery(headers, queryComponents);

                        ODataRequestMessageWrapper batchOperationRequestMessage = this.CreateRequestMessage(XmlConstants.HttpMethodGet, requestUri, headers, this.RequestInfo.HttpStack, null /*descriptor*/, null /*contentId*/);

                        batchOperationRequestMessage.FireSendingEventHandlers(null /*descriptor*/);
                    }
                }
                else if (0 < this.ChangedEntries.Count)
                {
                    if (Util.IsBatchWithSingleChangeset(this.Options))
                    {
                        this.batchWriter.WriteStartChangeset();
                    }

                    var model = this.RequestInfo.Model;

                    for (int i = 0; i < this.ChangedEntries.Count; ++i)
                    {
                        if (Util.IsBatchWithIndependentOperations(this.Options))
                        {
                            this.batchWriter.WriteStartChangeset();
                        }

                        Descriptor descriptor = this.ChangedEntries[i];
                        if (descriptor.ContentGeneratedForSave)
                        {
                            continue;
                        }

                        EntityDescriptor entityDescriptor = descriptor as EntityDescriptor;
                        if (descriptor.DescriptorKind == DescriptorKind.Entity)
                        {
                            if (entityDescriptor.State == EntityStates.Added)
                            {
                                // We don't support adding MLE/MR in batch mode
                                ClientTypeAnnotation type = model.GetClientTypeAnnotation(model.GetOrCreateEdmType(entityDescriptor.Entity.GetType()));
                                if (type.IsMediaLinkEntry || entityDescriptor.IsMediaLinkEntry)
                                {
                                    throw Error.NotSupported(Strings.Context_BatchNotSupportedForMediaLink);
                                }
                            }
                            else if (entityDescriptor.State == EntityStates.Unchanged || entityDescriptor.State == EntityStates.Modified)
                            {
                                // We don't support PUT for the MR in batch mode
                                // It's OK to PUT the MLE alone inside a batch mode though
                                if (entityDescriptor.SaveStream != null)
                                {
                                    throw Error.NotSupported(Strings.Context_BatchNotSupportedForMediaLink);
                                }
                            }
                        }
                        else if (descriptor.DescriptorKind == DescriptorKind.NamedStream)
                        {
                            // Similar to MR, we do not support adding named streams in batch mode.
                            throw Error.NotSupported(Strings.Context_BatchNotSupportedForNamedStreams);
                        }

                        ODataRequestMessageWrapper operationRequestMessage;
                        if (descriptor.DescriptorKind == DescriptorKind.Entity)
                        {
                            operationRequestMessage = this.CreateRequest(entityDescriptor);
                        }
                        else
                        {
                            operationRequestMessage = this.CreateRequest((LinkDescriptor)descriptor);
                        }

                        // we need to fire request after the headers have been written, but before we write the payload
                        operationRequestMessage.FireSendingRequest2(descriptor);

                        this.CreateChangeData(i, operationRequestMessage);

                        if (Util.IsBatchWithIndependentOperations(this.Options))
                        {
                            this.batchWriter.WriteEndChangeset();
                        }
                    }

                    if (Util.IsBatchWithSingleChangeset(this.Options))
                    {
                        this.batchWriter.WriteEndChangeset();
                    }
                }

                this.batchWriter.WriteEndBatch();
                this.batchWriter.Flush();
            }

            Debug.Assert(this.ChangedEntries.All(o => o.ContentGeneratedForSave), "didn't generated content for all entities/links");
            return(batchRequestMessage);
        }
예제 #2
0
        /// <summary>
        /// Create request message from the next change.
        /// </summary>
        /// <returns>An instance of ODataRequestMessage for the next change.</returns>
        private ODataRequestMessageWrapper CreateNextRequest()
        {
            bool moveForward = this.streamRequestKind == StreamRequestKind.None;

            if (unchecked ((uint)this.entryIndex < (uint)this.ChangedEntries.Count))
            {
                Descriptor previousDescriptor = this.ChangedEntries[this.entryIndex];
                if (previousDescriptor.DescriptorKind == DescriptorKind.Entity)
                {
                    EntityDescriptor entityDescriptor = (EntityDescriptor)previousDescriptor;

                    // In any case also close the save stream if there's any and forget about it
                    // for POST this is just a good practice to do so as soon as possible
                    // for PUT it's actually required for us to recognize that we already processed the MR part of the change
                    entityDescriptor.CloseSaveStream();

                    // If the previous request was an MR request the next one might be a PUT for the MLE
                    //   but if the entity was not changed (just the MR changed) no PUT for MLE should be sent
                    if (this.streamRequestKind == StreamRequestKind.PutMediaResource && EntityStates.Unchanged == entityDescriptor.State)
                    {
                        // Only the MR changed. In this case we also need to mark the descriptor as processed to notify
                        //   that the content for save has been generated as there's not going to be another request for it.
                        entityDescriptor.ContentGeneratedForSave = true;
                        moveForward = true;
                    }
                }
                else if (previousDescriptor.DescriptorKind == DescriptorKind.NamedStream)
                {
                    ((StreamDescriptor)previousDescriptor).CloseSaveStream();
                }
            }

            if (moveForward)
            {
                this.entryIndex++;
            }

            ODataRequestMessageWrapper requestMessage = null;

            if (unchecked ((uint)this.entryIndex < (uint)this.ChangedEntries.Count))
            {
                Descriptor descriptor = this.ChangedEntries[this.entryIndex];
                Descriptor descriptorForSendingRequest2 = descriptor;
                if (descriptor.DescriptorKind == DescriptorKind.Entity)
                {
                    EntityDescriptor entityDescriptor = (EntityDescriptor)descriptor;

                    if (((descriptor.State == EntityStates.Unchanged) || (descriptor.State == EntityStates.Modified)) &&
                        ((requestMessage = this.CheckAndProcessMediaEntryPut(entityDescriptor)) != null))
                    {
                        this.streamRequestKind       = StreamRequestKind.PutMediaResource;
                        descriptorForSendingRequest2 = entityDescriptor.DefaultStreamDescriptor;  // We want to give SendingRequest2 the StreamDescriptor
                    }
                    else if ((descriptor.State == EntityStates.Added) && ((requestMessage = this.CheckAndProcessMediaEntryPost(entityDescriptor)) != null))
                    {
                        this.streamRequestKind = StreamRequestKind.PostMediaResource;

                        Debug.Assert(entityDescriptor.SaveStream == null || entityDescriptor.StreamState == EntityStates.Added, "Either this is a V1 MR or the stream must be in added state");

                        // Set the stream state to added
                        // For V1 scenarios, when SetSaveStream was not called, this might not be in Added state
                        entityDescriptor.StreamState = EntityStates.Added;
                    }
                    else
                    {
                        this.streamRequestKind = StreamRequestKind.None;
                        Debug.Assert(descriptor.State != EntityStates.Unchanged, "descriptor.State != EntityStates.Unchanged");
                        requestMessage = this.CreateRequest(entityDescriptor);
                    }
                }
                else if (descriptor.DescriptorKind == DescriptorKind.NamedStream)
                {
                    requestMessage = this.CreateNamedStreamRequest((StreamDescriptor)descriptor);
                }
                else
                {
                    requestMessage = this.CreateRequest((LinkDescriptor)descriptor);
                }

                if (requestMessage != null)
                {
                    // we need to fire request after the headers have been written, but before we write the payload
                    // also in the prototype we are firing SendingRequest2 before SendingRequest.
                    requestMessage.FireSendingEventHandlers(descriptorForSendingRequest2);
                }
            }

            return(requestMessage);
        }