Exemple #1
0
        /// <summary>
        /// Executes SaveChanges on the specified context and with specified options and verifies the results.
        /// </summary>
        /// <param name="verifier">The verifier to use for verification.</param>
        /// <param name="contextData">The data for the context.</param>
        /// <param name="context">The context to verify SaveChanges on.</param>
        /// <param name="options">The options for saving changes.</param>
        /// <returns>The response from SaveChanges</returns>
        public static DSClient.DataServiceResponse VerifySaveChanges(this ISaveChangesVerifier verifier, DataServiceContextData contextData, DSClient.DataServiceContext context, SaveChangesOptions?options)
        {
            ExceptionUtilities.CheckArgumentNotNull(verifier, "verifier");
            ExceptionUtilities.CheckArgumentNotNull(contextData, "contextData");
            ExceptionUtilities.CheckArgumentNotNull(context, "context");

            DSClient.DataServiceResponse response = null;
            SyncHelpers.ExecuteActionAndWait(c1 => verifier.VerifySaveChanges(c1, contextData, context, options, (c2, r) => { response = r; c2.Continue(); }));
            return(response);
        }
Exemple #2
0
        /// <summary>
        /// process the batch response
        /// </summary>
        /// <param name="batchReader">The batch reader to use for reading the batch response.</param>
        /// <returns>an instance of the DataServiceResponse, containing individual operation responses for this batch request.</returns>
        /// <remarks>
        /// The message reader for the entire batch response is stored in the this.batchMessageReader.
        /// The message reader is disposable, but this method should not dispose it itself. It will be either disposed by the caller (in case of exception)
        /// or the ownership will be passed to the returned response object (in case of success).
        /// In could also be diposed indirectly by this method when it enumerates through the responses.
        /// </remarks>
        private DataServiceResponse HandleBatchResponseInternal(ODataBatchReader batchReader)
        {
            Debug.Assert(this.batchMessageReader != null, "this.batchMessageReader != null");
            Debug.Assert(batchReader != null, "batchReader != null");

            DataServiceResponse response;
            HeaderCollection    headers = new HeaderCollection(this.batchResponseMessage);

            IEnumerable <OperationResponse> responses = this.HandleBatchResponse(batchReader);

            if (this.Queries != null)
            {
                // ExecuteBatch, EndExecuteBatch
                response = new DataServiceResponse(
                    headers,
                    (int)this.batchResponseMessage.StatusCode,
                    responses,
                    true /*batchResponse*/);
            }
            else
            {
                List <OperationResponse> operationResponses = new List <OperationResponse>();
                response = new DataServiceResponse(headers, (int)this.batchResponseMessage.StatusCode, operationResponses, true /*batchResponse*/);
                Exception exception = null;

                // SaveChanges, EndSaveChanges
                // enumerate the entire response
                foreach (ChangeOperationResponse changeOperationResponse in responses)
                {
                    operationResponses.Add(changeOperationResponse);
                    if (Util.IsBatchWithSingleChangeset(this.Options) && exception == null && changeOperationResponse.Error != null)
                    {
                        exception = changeOperationResponse.Error;
                    }

                    // Note that this will dispose the enumerator and this release the batch message reader which is owned
                    // by the enumerable of responses by now.
                }

                // Note that if we encounter any error in a batch request with a single changeset,
                // we throw here since all change operations in the changeset are rolled back on the server.
                // If we encounter any error in a batch request with independent operations, we don't want to throw
                // since some of the operations might succeed.
                // Users need to inspect each OperationResponse to get the exception information from the failed operations.
                if (exception != null)
                {
                    throw new DataServiceRequestException(Strings.DataServiceException_GeneralError, exception, response);
                }
            }

            return(response);
        }
Exemple #3
0
        /// <summary>
        /// This method creates a new reservation record for the customer, created by the CreateCustomer method.
        /// </summary>
        /// <param name="customer"></param>
        /// <returns></returns>
        private static FleetRental CreateReservation(FleetCustomer customer)
        {
            Random rnd = new Random();

            DataServiceCollection <FleetRental> reservations = new DataServiceCollection <FleetRental>(context);

            FleetRental reservation = new FleetRental();

            reservations.Add(reservation);
            //Create a new Reservation object with the details for new customer.


            reservation.CustomerFirstName     = customer.FirstName;
            reservation.CustomerLastName      = customer.LastName;
            reservation.CustomerDriverLicense = customer.DriverLicense;
            reservation.State      = 0; //Limitation of OData, no client-side Enum support
            reservation.RentalId   = "OData_" + rnd.Next(500).ToString();
            reservation.Comments   = "New customer";
            reservation.VehicleId  = "Adatum_Four_2";
            reservation.VehicleVIN = "WAUXL58E15A104563";
            reservation.EndDate    = DateTime.Today.AddDays(5);
            reservation.StartDate  = DateTime.Today;


            Microsoft.OData.Client.DataServiceResponse response = null;
            try
            {
                response = context.SaveChanges(SaveChangesOptions.PostOnlySetProperties);
            }
            catch (DataServiceRequestException e)
            {
                Console.WriteLine("Error occured while saving. Error Details: " + e.InnerException.Message);
            }


            //the following code retrieves the location header which represents the newly created entity
            Console.ForegroundColor = ConsoleColor.Cyan;
            foreach (ChangeOperationResponse r in response)
            {
                if (r.Headers.ContainsKey("Location"))
                {
                    Console.ForegroundColor = ConsoleColor.Cyan;
                    Console.WriteLine("New reservation created: ");
                    Console.WriteLine(r.Headers["Location"]);
                }
            }
            Console.ForegroundColor = ConsoleColor.White;

            return(reservation);
        }
Exemple #4
0
        /// <summary>
        /// This method prompts the user for first name and last name and then uses that to create a new customer by calling the Customer OData entity
        /// </summary>
        /// <returns></returns>
        private static FleetCustomer CreateCustomer()
        {
            Console.WriteLine("Enter First Name, and then press Enter");
            string firstName = Console.ReadLine();

            Console.WriteLine("Enter Last Name, and then press Enter ");
            string lastName = Console.ReadLine();

            Random rnd = new Random();

            //Create the Customer object with the first and last names provided by the user
            FleetCustomer newCustomer = new FleetCustomer()
            {
                FirstName     = firstName,
                LastName      = lastName,
                DriverLicense = "B923-2381-" + rnd.Next(1000, 7000).ToString(),
                CellPhone     = "0123456789",
                Email         = "*****@*****.**",
            };

            //Add the new customer object to the DataServiceContext object
            context.AddToFleetCustomers(newCustomer);

            //Save the DataServiceContext object and an internally a POST call is made to the OData Customer entity.
            //Record is created in Rainier Database
            Microsoft.OData.Client.DataServiceResponse response = null;
            try
            {
                response = context.SaveChanges();
            }
            catch (DataServiceRequestException e)
            {
                Console.WriteLine("Error occured while saving. Error Details: " + e.InnerException.Message);
            }

            //the following code retrieves the location header which represents the newly created entity
            foreach (ChangeOperationResponse r in response)
            {
                if (r.Headers.ContainsKey("Location"))
                {
                    Console.ForegroundColor = ConsoleColor.Cyan;
                    Console.WriteLine("New customer created: ");
                    Console.WriteLine(r.Headers["Location"]);
                }
            }

            Console.ForegroundColor = ConsoleColor.White;

            return(newCustomer);
        }
Exemple #5
0
        /// <summary>
        /// Executes SaveChanges on the specified context and with specified options and verifies the results.
        /// </summary>
        /// <param name="verifier">The verifier to use for verification.</param>
        /// <param name="contextData">The data for the context.</param>
        /// <param name="context">The context to verify SaveChanges on.</param>
        /// <param name="options">The options for saving changes.</param>
        /// <returns>The response from SaveChanges</returns>
        public static DSClient.DataServiceResponse VerifySaveChanges(this ISaveChangesVerifier verifier, DataServiceContextData contextData, DSClient.DataServiceContext context, SaveChangesOptions? options)
        {
#if SILVERLIGHT
            throw new TaupoNotSupportedException("Not supported in Silverlight");
#else
            ExceptionUtilities.CheckArgumentNotNull(verifier, "verifier");
            ExceptionUtilities.CheckArgumentNotNull(contextData, "contextData");
            ExceptionUtilities.CheckArgumentNotNull(context, "context");

            DSClient.DataServiceResponse response = null;
            SyncHelpers.ExecuteActionAndWait(c1 => verifier.VerifySaveChanges(c1, contextData, context, options, (c2, r) => { response = r; c2.Continue(); }));
            return response;
#endif
        }
Exemple #6
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);
        }
Exemple #7
0
        /// <summary>
        /// process the batch response
        /// </summary>
        /// <returns>an instance of the DataServiceResponse, containing individual operation responses for this batch request.</returns>
        private DataServiceResponse HandleBatchResponse()
        {
            bool batchMessageReaderOwned = true;

            try
            {
                if ((this.batchResponseMessage == null) || (this.batchResponseMessage.StatusCode == (int)HttpStatusCode.NoContent))
                {   // we always expect a response to our batch POST request
                    throw Error.InvalidOperation(Strings.Batch_ExpectedResponse(1));
                }

                Func <Stream> getResponseStream = () => this.ResponseStream;

                // We are not going to use the responseVersion returned from this call, as the $batch request itself doesn't apply versioning
                // of the responses on the root level. The responses are versioned on the part level. (Note that the version on the $batch level
                // is actually used to version the batch itself, but we for now we only recognize a single version so to keep it backward compatible
                // we don't check this here. Also note that the HandleResponse method will verify that we can support the version, that is it's
                // lower than the highest version we understand).
                Version responseVersion;
                BaseSaveResult.HandleResponse(
                    this.RequestInfo,
                    (HttpStatusCode)this.batchResponseMessage.StatusCode,               // statusCode
                    this.batchResponseMessage.GetHeader(XmlConstants.HttpODataVersion), // responseVersion
                    getResponseStream,                                                  // getResponseStream
                    true,                                                               // throwOnFailure
                    out responseVersion);

                if (this.ResponseStream == null)
                {
                    Error.ThrowBatchExpectedResponse(InternalError.NullResponseStream);
                }

                // Create the message and the message reader.
                this.batchResponseMessage = new HttpWebResponseMessage(new HeaderCollection(this.batchResponseMessage), this.batchResponseMessage.StatusCode, getResponseStream);
                ODataMessageReaderSettings messageReaderSettings = this.RequestInfo.GetDeserializationInfo(/*mergeOption*/ null).ReadHelper.CreateSettings();

                // No need to pass in any model to the batch reader.
                this.batchMessageReader = new ODataMessageReader(this.batchResponseMessage, messageReaderSettings);
                ODataBatchReader batchReader;
                try
                {
                    batchReader = this.batchMessageReader.CreateODataBatchReader();
                }
                catch (ODataContentTypeException contentTypeException)
                {
                    string    mime;
                    Encoding  encoding;
                    Exception inner = contentTypeException;
                    ContentTypeUtil.ReadContentType(this.batchResponseMessage.GetHeader(XmlConstants.HttpContentType), out mime, out encoding);
                    if (String.Equals(XmlConstants.MimeTextPlain, mime))
                    {
                        inner = GetResponseText(
                            this.batchResponseMessage.GetStream,
                            (HttpStatusCode)this.batchResponseMessage.StatusCode);
                    }

                    throw Error.InvalidOperation(Strings.Batch_ExpectedContentType(this.batchResponseMessage.GetHeader(XmlConstants.HttpContentType)), inner);
                }

                DataServiceResponse response = this.HandleBatchResponseInternal(batchReader);

                // In case of successful processing of at least the beginning of the batch, the message reader is owned by the returned response
                // (or rather by the IEnumerable of operation responses inside it).
                // It will be disposed once the operation responses are enumerated (since the IEnumerator should be disposed once used).
                // In that case we must NOT dispose it here, since that enumeration can exist long after we return from this method.
                batchMessageReaderOwned = false;

                return(response);
            }
            catch (DataServiceRequestException)
            {
                throw;
            }
            catch (InvalidOperationException ex)
            {
                HeaderCollection headers     = new HeaderCollection(this.batchResponseMessage);
                int statusCode               = this.batchResponseMessage == null ? (int)HttpStatusCode.InternalServerError : (int)this.batchResponseMessage.StatusCode;
                DataServiceResponse response = new DataServiceResponse(headers, statusCode, new OperationResponse[0], this.IsBatchRequest);
                throw new DataServiceRequestException(Strings.DataServiceException_GeneralError, ex, response);
            }
            finally
            {
                if (batchMessageReaderOwned)
                {
                    Util.Dispose(ref this.batchMessageReader);
                }
            }
        }
 /// <summary>
 /// Construct a DataServiceSaveChangesEventArgs object.
 /// </summary>
 /// <param name="response">DataServiceContext SaveChanges response</param>
 public SaveChangesEventArgs(DataServiceResponse response)
 {
     this.response = response;
 }
 /// <summary>Initializes a new instance of the <see cref="T:Microsoft.OData.Client.DataServiceRequestException" /> class. </summary>
 /// <param name="message">Error message text.</param>
 /// <param name="innerException">Exception object that contains the inner exception.</param>
 /// <param name="response"><see cref="T:Microsoft.OData.Client.DataServiceResponse" /> object.</param>
 public DataServiceRequestException(string message, Exception innerException, DataServiceResponse response)
     : base(message, innerException)
 {
     this.response = response;
 }
Exemple #10
0
        /// <summary>
        /// Tracks the SaveChanges method.
        /// </summary>
        /// <param name="data">The data service context data on which to apply state transition.</param>
        /// <param name="options">The options.</param>
        /// <param name="response">The response.</param>
        /// <param name="cachedOperationsFromResponse">The individual operation respones, pre-enumerated and cached.</param>
        /// <param name="tracker">The entity data change tracker to use</param>
        public static void TrackSaveChanges(this DataServiceContextData data, SaveChangesOptions options, DSClient.DataServiceResponse response, IEnumerable <DSClient.OperationResponse> cachedOperationsFromResponse, IEntityDescriptorDataChangeTracker tracker)
        {
            ExceptionUtilities.CheckArgumentNotNull(data, "data");
            ExceptionUtilities.CheckArgumentNotNull(response, "response");
            ExceptionUtilities.CheckArgumentNotNull(cachedOperationsFromResponse, "cachedOperationsFromResponse");
            ExceptionUtilities.CheckArgumentNotNull(tracker, "tracker");

            // Check options and response consistency
            if ((options & SaveChangesOptions.ContinueOnError) == 0)
            {
                ExceptionUtilities.Assert(response.Count(r => r.Error != null) == 0, "Check save changes options and response consistency: no errors in the response when ContinueOnError is off.");
            }

            // because some links will not have separate requests, we need to keep track of all link changes
            var allPendingLinkChanges = data.GetOrderedChanges().OfType <LinkDescriptorData>().ToList();

            // go through the pending changes and update the states based on whether the request succeeded
            foreach (DSClient.ChangeOperationResponse changeResponse in cachedOperationsFromResponse)
            {
                DescriptorData       descriptorData;
                LinkDescriptorData   linkDescriptorData   = null;
                StreamDescriptorData streamDescriptorData = null;
                var entityDescriptor = changeResponse.Descriptor as DSClient.EntityDescriptor;
                if (entityDescriptor != null)
                {
                    descriptorData = data.GetEntityDescriptorData(entityDescriptor.Entity);
                }
                else
                {
                    var linkDescriptor = changeResponse.Descriptor as DSClient.LinkDescriptor;
                    if (linkDescriptor != null)
                    {
                        linkDescriptorData = data.GetLinkDescriptorData(linkDescriptor.Source, linkDescriptor.SourceProperty, linkDescriptor.Target);
                        descriptorData     = linkDescriptorData;
                        allPendingLinkChanges.Remove(linkDescriptorData);
                    }
                    else
                    {
                        // for stream descriptors, we need to find the parent descriptor, then get the stream descriptor data from it
                        var streamDescriptor = (DSClient.StreamDescriptor)changeResponse.Descriptor;

                        entityDescriptor     = streamDescriptor.EntityDescriptor;
                        streamDescriptorData = data.GetStreamDescriptorData(entityDescriptor.Entity, streamDescriptor.StreamLink.Name);
                        descriptorData       = streamDescriptorData;
                    }
                }

                // don't update states for responses that indicate failure
                if (changeResponse.Error != null)
                {
                    continue;
                }

                // because the request succeeded, make the corresponding updates to the states
                if (descriptorData.State == EntityStates.Deleted ||
                    (linkDescriptorData != null &&
                     linkDescriptorData.State == EntityStates.Modified &&
                     linkDescriptorData.SourceDescriptor.State == EntityStates.Deleted))
                {
                    data.RemoveDescriptorData(descriptorData);
                }
                else
                {
                    // for non-deleted descriptors, we need to update states based on the headers
                    var entityDescriptorData = descriptorData as EntityDescriptorData;
                    if (entityDescriptorData != null)
                    {
                        if (entityDescriptorData.IsMediaLinkEntry && entityDescriptorData.DefaultStreamState == EntityStates.Modified)
                        {
                            entityDescriptorData.DefaultStreamDescriptor.UpdateFromHeaders(changeResponse.Headers);
                            entityDescriptorData.DefaultStreamState = EntityStates.Unchanged;
                        }
                        else
                        {
                            if (entityDescriptorData.IsMediaLinkEntry && entityDescriptorData.DefaultStreamState == EntityStates.Added)
                            {
                                entityDescriptorData.DefaultStreamState = EntityStates.Unchanged;
                            }

                            // because there might have been a reading-entity event for this entity, we need to apply the headers through the tracker
                            tracker.TrackUpdateFromHeaders(entityDescriptorData, changeResponse.Headers);

                            // ensure that all updates are applied before moving to the next response
                            tracker.ApplyPendingUpdates(entityDescriptorData);

                            entityDescriptorData.ParentForInsert         = null;
                            entityDescriptorData.ParentPropertyForInsert = null;
                            entityDescriptorData.InsertLink = null;
                        }
                    }
                    else if (streamDescriptorData != null)
                    {
                        streamDescriptorData.UpdateFromHeaders(changeResponse.Headers);
                    }

                    descriptorData.State = EntityStates.Unchanged;
                }
            }

            // go through each link change that did not have an assocatiated response and update its state
            foreach (var linkDescriptorData in allPendingLinkChanges.OfType <LinkDescriptorData>())
            {
                if (linkDescriptorData.State == EntityStates.Added || linkDescriptorData.State == EntityStates.Modified)
                {
                    linkDescriptorData.State = EntityStates.Unchanged;
                }
            }
        }
 public DataServiceResponseWrapper(DataServiceResponse response)
 {
     this._DataServiceResponse = response;
 }