private ExpectedClientRequest CreateSaveStreamRequest(StreamDescriptorData streamDescriptorData, Uri requestUri) { HttpVerb verb; if (streamDescriptorData.State == EntityStates.Added) { verb = HttpVerb.Post; } else { ExceptionUtilities.Assert(streamDescriptorData.State == EntityStates.Modified, "Stream descriptor state should only be added or modified. State was: '{0}'", streamDescriptorData.State); verb = HttpVerb.Put; } var request = new ExpectedClientRequest() { Verb = verb, Uri = requestUri }; foreach (var header in streamDescriptorData.SaveStream.Headers) { request.Headers.Add(header); } request.Body = new PrimitiveValue(null, streamDescriptorData.SaveStream.StreamLogger.GetAllBytesRead()); return(request); }
private void VerifyStreamClosed(StreamDescriptorData streamDescriptor) { var saveStream = streamDescriptor.SaveStream; if (saveStream != null) { this.parent.Assert.IsTrue(saveStream.StreamLogger.IsEndOfStream, string.Format(CultureInfo.InvariantCulture, "Stream was not read to the end: {0}", streamDescriptor)); this.parent.Assert.AreEqual( saveStream.CloseStream, saveStream.StreamLogger.IsClosed, string.Format(CultureInfo.InvariantCulture, "Save stream should/should not have been closed: {0}", streamDescriptor)); streamDescriptor.SaveStream = null; } }
private void VerifyDescriptor(DescriptorData expected, Descriptor actual, int responseOrder) { EntityDescriptorData entityDescriptorData = expected as EntityDescriptorData; LinkDescriptorData linkDescriptorData = expected as LinkDescriptorData; StreamDescriptorData streamDescriptorData = expected as StreamDescriptorData; if (entityDescriptorData != null) { EntityDescriptor entityDescriptor = actual as EntityDescriptor; this.Assert.IsNotNull(entityDescriptor, GetVerificationFailureMessage(responseOrder, "Unexpected descriptor type:\r\nExpected: {0}\r\nActual: {1}\r\nExpected descriptor data: {2}.", typeof(EntityDescriptor).Name, actual.GetType().Name, entityDescriptorData)); this.Assert.AreSame( entityDescriptorData.Entity, entityDescriptor.Entity, GetVerificationFailureMessage(responseOrder, "Entity verification failed for the entity descriptor data: {0}.", expected)); } else if (linkDescriptorData != null) { LinkDescriptor linkDescriptor = actual as LinkDescriptor; this.Assert.IsNotNull(linkDescriptor, GetVerificationFailureMessage(responseOrder, "Unexpected descriptor type:\r\nExpected: {0}\r\nActual: {1}\r\nExpected descriptor data: {2}.", typeof(LinkDescriptor).Name, actual.GetType().Name, linkDescriptorData)); bool notMatch = linkDescriptorData.SourceDescriptor.Entity != linkDescriptor.Source || (linkDescriptorData.TargetDescriptor == null && linkDescriptor.Target != null) || (linkDescriptorData.TargetDescriptor != null && linkDescriptorData.TargetDescriptor.Entity != linkDescriptor.Target) || linkDescriptorData.SourcePropertyName != linkDescriptor.SourceProperty; this.Assert.IsFalse(notMatch, GetVerificationFailureMessage(responseOrder, "Link verification failed.\r\nExpected: {0}\r\nActual: {1}", linkDescriptorData, linkDescriptor.ToTraceString())); } else { #if WINDOWS_PHONE throw new TaupoNotSupportedException("StreamDescriptors are not supported on Windows Phone"); #else ExceptionUtilities.CheckObjectNotNull(streamDescriptorData, "Expected was not an entity, link, or stream descriptor: {0}", expected); StreamDescriptor streamDescriptor = actual as StreamDescriptor; this.Assert.IsNotNull(streamDescriptor, GetVerificationFailureMessage(responseOrder, "Unexpected descriptor type:\r\nExpected: {0}\r\nActual: {1}\r\nExpected descriptor data: {2}.", typeof(StreamDescriptor).Name, actual.GetType().Name, streamDescriptorData)); this.Assert.AreEqual(streamDescriptorData.State.ToProductEnum(), streamDescriptor.State, GetVerificationFailureMessage(responseOrder, "Stream descriptor state verification failed.")); this.Assert.AreEqual(streamDescriptorData.Name, streamDescriptor.StreamLink.Name, GetVerificationFailureMessage(responseOrder, "Stream descriptor name verification failed.")); this.Assert.AreEqual(streamDescriptorData.ETag, streamDescriptor.StreamLink.ETag, GetVerificationFailureMessage(responseOrder, "Stream descriptor etag verification failed.")); this.Assert.AreEqual(streamDescriptorData.ContentType, streamDescriptor.StreamLink.ContentType, GetVerificationFailureMessage(responseOrder, "Stream descriptor content type verification failed.")); this.Assert.AreEqual(streamDescriptorData.EditLink, streamDescriptor.StreamLink.EditLink, GetVerificationFailureMessage(responseOrder, "Stream descriptor edit link verification failed.")); this.Assert.AreEqual(streamDescriptorData.SelfLink, streamDescriptor.StreamLink.SelfLink, GetVerificationFailureMessage(responseOrder, "Stream descriptor self link verification failed.")); #endif } }
private ExpectedClientRequest CreateStreamUpdateRequest(StreamDescriptorData streamDescriptorData, SaveChangesOptions options) { var request = this.CreateSaveStreamRequest(streamDescriptorData, streamDescriptorData.EditLink); request.Headers[HttpHeaders.IfMatch] = streamDescriptorData.ETag; request.Headers[HttpHeaders.Prefer] = null; request.Headers[HttpHeaders.DataServiceVersion] = ToClientHeaderFormat(DataServiceProtocolVersion.V4); this.SetDefaultAcceptHeader(request, options); SetContentTypeHeaderForStream(request, streamDescriptorData); string hintString = @"Stream update\r\n{{\r\n Descriptor = {0}\r\n\r\n}}"; request.DebugHintString = string.Format(CultureInfo.InvariantCulture, hintString, streamDescriptorData); return(request); }
private ExpectedClientRequest CreateStreamInsertRequest(DataServiceContextData contextData, StreamDescriptorData streamDescriptorData, SaveChangesOptions options) { ExceptionUtilities.Assert(streamDescriptorData.Name == null, "Can only be used for media-resources"); var insertUri = GetEntityInsertUri(contextData, streamDescriptorData.EntityDescriptor); var request = this.CreateSaveStreamRequest(streamDescriptorData, insertUri); string preference = contextData.AddAndUpdateResponsePreference.ToHeaderValue(); var dsv = GetDataServiceVersion(request.Verb, preference); request.Headers[HttpHeaders.DataServiceVersion] = ToClientHeaderFormat(dsv); request.Headers[HttpHeaders.IfMatch] = null; request.Headers[HttpHeaders.Prefer] = preference; this.SetDefaultAcceptHeader(request, options); SetContentTypeHeaderForStream(request, streamDescriptorData); string hintString = @"Stream insert\r\n{{\r\n Descriptor = {0}\r\n\r\n}}"; request.DebugHintString = string.Format(CultureInfo.InvariantCulture, hintString, streamDescriptorData); return(request); }
private static void SetContentTypeHeaderForStream(ExpectedClientRequest request, StreamDescriptorData streamDescriptorData) { request.Headers[HttpHeaders.ContentType] = streamDescriptorData.ContentType; if (streamDescriptorData.ContentType == null) { request.Headers[HttpHeaders.ContentType] = MimeTypes.Any; } foreach (var header in streamDescriptorData.SaveStream.Headers) { request.Headers[header.Key] = header.Value; } request.Headers[HttpHeaders.Accept] = DefaultAccept; }
/// <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; } } }