/// <summary> /// Initializes a new instance of the <see cref="EntityDescriptorData"/> class. /// </summary> /// <param name="contextData">The context data which contains this entity descriptor data</param> /// <param name="entity">The entity.</param> internal EntityDescriptorData(DataServiceContextData contextData, object entity) : this(contextData) { ExceptionUtilities.CheckArgumentNotNull(entity, "entity"); this.entity = entity; this.EntityClrType = entity.GetType(); }
/// <summary> /// Initializes a new instance of the EntityDescriptorData class /// </summary> /// <param name="contextData">The context data which contains this entity descriptor data</param> private EntityDescriptorData(DataServiceContextData contextData) { ExceptionUtilities.CheckArgumentNotNull(contextData, "contextData"); this.contextData = contextData; this.linkInfos = new List<LinkInfoData>(); this.operationDescriptors = new List<OperationDescriptorData>(); this.streamDescriptors = new List<StreamDescriptorData>(); }
/// <summary> /// Initializes a new instance of the <see cref="EntityDescriptorData"/> class. /// </summary> /// <param name="contextData">The context data which contains this entity descriptor data</param> /// <param name="identity">The entity identity.</param> /// <param name="entityClrType">Type of the entity.</param> internal EntityDescriptorData(DataServiceContextData contextData, Uri identity, Type entityClrType) : this(contextData) { ExceptionUtilities.CheckArgumentNotNull(entityClrType, "entityClrType"); this.EntityClrType = entityClrType; this.Identity = identity; }
/// <summary> /// Initializes a new instance of the <see cref="EntityDescriptorData"/> class. /// </summary> /// <param name="contextData">The context data which contains this entity descriptor data</param> /// <param name="entity">The entity.</param> internal EntityDescriptorData(DataServiceContextData contextData, object entity) : this(contextData) { ExceptionUtilities.CheckArgumentNotNull(entity, "entity"); this.entity = entity; this.EntityClrType = entity.GetType(); }
/// <summary> /// Initializes a new instance of the EntityDescriptorData class /// </summary> /// <param name="contextData">The context data which contains this entity descriptor data</param> private EntityDescriptorData(DataServiceContextData contextData) { ExceptionUtilities.CheckArgumentNotNull(contextData, "contextData"); this.contextData = contextData; this.linkInfos = new List <LinkInfoData>(); this.operationDescriptors = new List <OperationDescriptorData>(); this.streamDescriptors = new List <StreamDescriptorData>(); }
/// <summary> /// Initializes a new instance of the <see cref="EntityDescriptorData"/> class. /// </summary> /// <param name="contextData">The context data which contains this entity descriptor data</param> /// <param name="identity">The entity identity.</param> /// <param name="entityClrType">Type of the entity.</param> internal EntityDescriptorData(DataServiceContextData contextData, Uri identity, Type entityClrType) : this(contextData) { ExceptionUtilities.CheckArgumentNotNull(entityClrType, "entityClrType"); this.EntityClrType = entityClrType; this.Identity = identity; }
/// <summary> /// Executes SaveChanges on the specified context and with the default 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> /// <returns>The response from SaveChanges</returns> public static DSClient.DataServiceResponse VerifySaveChanges(this ISaveChangesVerifier verifier, DataServiceContextData contextData, DSClient.DataServiceContext context) { ExceptionUtilities.CheckArgumentNotNull(verifier, "verifier"); ExceptionUtilities.CheckArgumentNotNull(contextData, "contextData"); ExceptionUtilities.CheckArgumentNotNull(context, "context"); return verifier.VerifySaveChanges(contextData, context, null); }
/// <summary> /// Validates the requests sent, updates the expected state, and produces the expected response data for a single call to SaveChanges /// </summary> /// <param name="contextData">The context data at the time save-changes was called</param> /// <param name="propertyValuesBeforeSave">The property values of the tracked client objects before the call to SaveChanges</param> /// <param name="options">The save changes options used</param> /// <param name="requestResponsePairs">The observed HTTP traffic during save-changes</param> /// <returns>The expected response data</returns> public DataServiceResponseData ValidateAndTrackChanges(DataServiceContextData contextData, IDictionary<object, IEnumerable<NamedValue>> propertyValuesBeforeSave, SaveChangesOptions options, IEnumerable<KeyValuePair<HttpRequestData, HttpResponseData>> requestResponsePairs) { ExceptionUtilities.CheckArgumentNotNull(contextData, "contextData"); ExceptionUtilities.CheckArgumentNotNull(requestResponsePairs, "requestResponsePairs"); var castPairs = requestResponsePairs.Select(p => new KeyValuePair<IHttpRequest, HttpResponseData>(p.Key, p.Value)); var emulator = new PipelineEmulator(this, contextData, propertyValuesBeforeSave, options, castPairs); return emulator.Run(); }
/// <summary> /// Extension method to either find or create a link descriptor with the given values /// </summary> /// <param name="contextData">The context data</param> /// <param name="sourceDescriptor">The source descriptor</param> /// <param name="propertyName">The property name</param> /// <param name="targetDescriptor">The target descriptor</param> /// <returns>A link descriptor with the given values</returns> public static LinkDescriptorData MaterializeLinkDescriptor(this DataServiceContextData contextData, EntityDescriptorData sourceDescriptor, string propertyName, EntityDescriptorData targetDescriptor) { var existingLink = contextData.LinkDescriptorsData.SingleOrDefault(l => l.SourceDescriptor == sourceDescriptor && l.SourcePropertyName == propertyName && l.TargetDescriptor == targetDescriptor); if (existingLink == null) { existingLink = contextData.CreateLinkDescriptorData(EntityStates.Unchanged, 0, sourceDescriptor, propertyName, targetDescriptor); } return(existingLink); }
/// <summary> /// Creates the data service context data from data service context. /// </summary> /// <param name="context">The context.</param> /// <param name="maxProtocolVersion">The max protocol version.</param> /// <returns>DataServiceContextData based on context</returns> public static DataServiceContextData CreateDataServiceContextDataFromDataServiceContext(DSClient.DataServiceContext context, DataServiceProtocolVersion maxProtocolVersion) { var contextData = new DataServiceContextData(context.GetType(), maxProtocolVersion); // set all the properties on the context data to the values from the context foreach (var productProperty in typeof(DSClient.DataServiceContext).GetProperties(true, false)) { var testProperty = typeof(DataServiceContextData).GetProperty(productProperty.Name, true, false); if (testProperty != null && testProperty.PropertyType.IsAssignableFrom(productProperty.PropertyType)) { var value = productProperty.GetValue(context, null); testProperty.SetValue(contextData, value, null); } } return contextData; }
/// <summary> /// Calculates an entity id based on the base uri, entity set resolver, set name, and entity key values /// </summary> /// <param name="contextData">The context data</param> /// <param name="entitySetName">the entity set name</param> /// <param name="entity">The entity to generate an id for</param> /// <returns>The id for the given entity</returns> public Uri CalculateEntityId(DataServiceContextData contextData, string entitySetName, object entity) { ExceptionUtilities.CheckArgumentNotNull(contextData, "contextData"); ExceptionUtilities.CheckStringArgumentIsNotNullOrEmpty(entitySetName, "entitySetName"); ExceptionUtilities.CheckArgumentNotNull(entity, "entity"); if (contextData.BaseUri != null) { ExceptionUtilities.Assert(contextData.BaseUri.IsAbsoluteUri, "Base uri must be absolute. Uri was: '{0}'", contextData.BaseUri.OriginalString); return new Uri(UriHelpers.ConcatenateUriSegments(contextData.BaseUri.AbsoluteUri, Uri.EscapeDataString(entitySetName) + this.CalculateEntityKey(entity))); } else { ExceptionUtilities.CheckObjectNotNull(contextData.ResolveEntitySet, "Entity set resolver cannot be null if base uri is null"); var resolvedUri = contextData.ResolveEntitySet(entitySetName); ExceptionUtilities.CheckObjectNotNull(resolvedUri, "Entity set resolver returned null for set name '{0}'", entitySetName); return new Uri(resolvedUri.AbsoluteUri + this.CalculateEntityKey(entity)); } }
/// <summary> /// Clones the current data service context data /// </summary> /// <returns>A clone of the current data service context data</returns> public DataServiceContextData Clone() { var clone = new DataServiceContextData(this.ContextType, this.MaxProtocolVersion); clone.nextChangeOrder = this.nextChangeOrder; if (this.BaseUri != null) { clone.BaseUri = new Uri(this.BaseUri.OriginalString, UriKind.RelativeOrAbsolute); } clone.AddAndUpdateResponsePreference = this.AddAndUpdateResponsePreference; clone.MergeOption = this.MergeOption; clone.ResolveEntitySet = this.ResolveEntitySet; clone.ResolveName = this.ResolveName; clone.ResolveType = this.ResolveType; clone.UsePostTunneling = this.UsePostTunneling; clone.HttpStack = this.HttpStack; var mapping = new Dictionary<EntityDescriptorData, EntityDescriptorData>(ReferenceEqualityComparer.Create<EntityDescriptorData>()); foreach (var entityDescriptor in this.entityDatas) { var clonedDescriptor = entityDescriptor.Clone(clone); mapping[entityDescriptor] = clonedDescriptor; clone.entityDatas.Add(clonedDescriptor); } foreach (var linkDescriptor in this.linkDatas) { EntityDescriptorData clonedSource = null; EntityDescriptorData clonedTarget = null; mapping.TryGetValue(linkDescriptor.SourceDescriptor, out clonedSource); if (linkDescriptor.TargetDescriptor != null) { mapping.TryGetValue(linkDescriptor.TargetDescriptor, out clonedTarget); } var clonedDescriptor = linkDescriptor.Clone(clonedSource, clonedTarget); clone.linkDatas.Add(clonedDescriptor); } return clone; }
/// <summary> /// Clones the current entity descriptor data /// </summary> /// <returns>A clone of the current entity descriptor data</returns> /// <param name="clonedContextData">The cloned context data which will contain the cloned entity descriptor data</param> public EntityDescriptorData Clone(DataServiceContextData clonedContextData) { var clone = new EntityDescriptorData(clonedContextData); clone.ChangeOrder = this.ChangeOrder; clone.entity = this.entity; clone.EntityClrType = this.EntityClrType; clone.EntitySetName = this.EntitySetName; clone.ETag = this.ETag; clone.Identity = this.Identity; clone.linkInfos.AddRange(this.linkInfos.Select(l => l.Clone())); clone.operationDescriptors.AddRange(this.operationDescriptors.Select(o => o.Clone())); clone.streamDescriptors.AddRange(this.streamDescriptors.Select(n => n.Clone(clone))); clone.ParentForInsert = this.ParentForInsert; clone.ParentPropertyForInsert = this.ParentPropertyForInsert; clone.State = this.State; if (this.EditLink != null) { clone.EditLink = new Uri(this.EditLink.OriginalString, UriKind.RelativeOrAbsolute); } if (this.SelfLink != null) { clone.SelfLink = new Uri(this.SelfLink.OriginalString, UriKind.RelativeOrAbsolute); } if (this.InsertLink != null) { clone.InsertLink = new Uri(this.InsertLink.OriginalString, UriKind.RelativeOrAbsolute); } if (this.IsMediaLinkEntry) { clone.defaultStreamDescriptor = this.defaultStreamDescriptor.Clone(clone); } return(clone); }
private ExpectedClientRequest CreateEntityUpdateRequest(DataServiceContextData contextData, IDictionary<object, IEnumerable<NamedValue>> propertyValuesBeforeSave, EntityDescriptorData entityDescriptorData, SaveChangesOptions options) { var request = new ExpectedClientRequest() { Verb = GetUpdateVerb(options), Uri = entityDescriptorData.EditLink, }; string preference = contextData.AddAndUpdateResponsePreference.ToHeaderValue(); var dsv = GetDataServiceVersion(request.Verb, preference); dsv = dsv.IncreaseVersionIfRequired(this.VersionCalculator.CalculateDataServiceVersion(entityDescriptorData, contextData.MaxProtocolVersion)); request.Headers[HttpHeaders.DataServiceVersion] = ToClientHeaderFormat(dsv); request.Headers[HttpHeaders.IfMatch] = entityDescriptorData.ETag; request.Headers[HttpHeaders.Prefer] = preference; this.SetDefaultAcceptHeader(request, options); this.SetContentTypeHeaderForEntity(request); request.Body = this.BuildEntityPayload(contextData, propertyValuesBeforeSave, entityDescriptorData, dsv); string hintString = @"Entity update\r\n{{\r\n Descriptor = {0}\r\n Options = {1}\r\n}}"; request.DebugHintString = string.Format(CultureInfo.InvariantCulture, hintString, entityDescriptorData, options); 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; }
/// <summary> /// Clones the current entity descriptor data /// </summary> /// <returns>A clone of the current entity descriptor data</returns> /// <param name="clonedContextData">The cloned context data which will contain the cloned entity descriptor data</param> public EntityDescriptorData Clone(DataServiceContextData clonedContextData) { var clone = new EntityDescriptorData(clonedContextData); clone.ChangeOrder = this.ChangeOrder; clone.entity = this.entity; clone.EntityClrType = this.EntityClrType; clone.EntitySetName = this.EntitySetName; clone.ETag = this.ETag; clone.Identity = this.Identity; clone.linkInfos.AddRange(this.linkInfos.Select(l => l.Clone())); clone.operationDescriptors.AddRange(this.operationDescriptors.Select(o => o.Clone())); clone.streamDescriptors.AddRange(this.streamDescriptors.Select(n => n.Clone(clone))); clone.ParentForInsert = this.ParentForInsert; clone.ParentPropertyForInsert = this.ParentPropertyForInsert; clone.State = this.State; if (this.EditLink != null) { clone.EditLink = new Uri(this.EditLink.OriginalString, UriKind.RelativeOrAbsolute); } if (this.SelfLink != null) { clone.SelfLink = new Uri(this.SelfLink.OriginalString, UriKind.RelativeOrAbsolute); } if (this.InsertLink != null) { clone.InsertLink = new Uri(this.InsertLink.OriginalString, UriKind.RelativeOrAbsolute); } if (this.IsMediaLinkEntry) { clone.defaultStreamDescriptor = this.defaultStreamDescriptor.Clone(clone); } return clone; }
private void AddFoldedLinksToEntityInsertPayload(DataServiceContextData contextData, EntityDescriptorData entityDescriptorData, EntityInstance payload) { var entityType = this.ModelSchema.EntityTypes.Single(t => t.FullName == entityDescriptorData.EntityClrType.FullName); foreach (var linkDescriptor in contextData.LinkDescriptorsData.Where(l => l.SourceDescriptor == entityDescriptorData)) { if (linkDescriptor.TargetDescriptor.State == EntityStates.Added) { continue; } var navigationProperty = entityType.AllNavigationProperties.Single(n => n.Name == linkDescriptor.SourcePropertyName); string contentType = MimeTypes.ApplicationAtomXml + ";type="; if (navigationProperty.ToAssociationEnd.Multiplicity == EndMultiplicity.Many) { contentType += "feed"; } else { contentType += "entry"; } // note: the edit-link is used rather than identity because the server needs to be able to query for the target entity // and the identity may not be an actual uri var link = new DeferredLink() { UriString = linkDescriptor.TargetDescriptor.EditLink.OriginalString } .WithContentType(contentType).WithTitleAttribute(linkDescriptor.SourcePropertyName); payload.Add(new NavigationPropertyInstance(linkDescriptor.SourcePropertyName, link)); } }
/// <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="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, WrappedDataServiceContext context, SaveChangesOptions options) { DataServiceContextData data = CheckParametersAndGetDataServiceContextData(verifier, context); return(verifier.VerifySaveChanges(data, (DSClient.DataServiceContext)context.Product, options)); }
/// <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); }
/// <summary> /// Calculates an edit link for based on the base uri, entity set resolver, set name, and entity key values /// </summary> /// <param name="contextData">The context data</param> /// <param name="entitySetName">the entity set name</param> /// <param name="entity">The entity to generate an edit link for</param> /// <returns>The edit link for the given entity</returns> public Uri CalculateEditLink(DataServiceContextData contextData, string entitySetName, object entity) { return this.CalculateEntityId(contextData, entitySetName, entity); }
/// <summary> /// Returns a value indicating whether the descriptor should be updated based on its state and the context's merge option /// </summary> /// <param name="contextData">The context data</param> /// <param name="descriptorData">The descriptor data</param> /// <param name="isNewDescriptor">A value indicating whether the descriptor has just been created</param> /// <returns>True if changes should be applied, false otherwise</returns> public static bool ShouldApplyChangeToDescriptor(this DataServiceContextData contextData, DescriptorData descriptorData, bool isNewDescriptor) { return(isNewDescriptor || contextData.MergeOption == MergeOption.OverwriteChanges || (contextData.MergeOption == MergeOption.PreserveChanges && descriptorData.State == EntityStates.Unchanged)); }
/// <summary> /// Initializes the expected changes to verify after SaveChanges completes /// </summary> /// <param name="contextData">The context data</param> /// <param name="propertyValues">The property values of the tracked client objects</param> public void InitializeExpectedChanges(DataServiceContextData contextData, IDictionary<object, IEnumerable<NamedValue>> propertyValues) { this.expectedChangeCache[contextData] = contextData.GetOrderedChanges().Where(d => !(d is StreamDescriptorData)).Select(d => this.CreateChangeData(d, propertyValues)).ToList(); }
/// <summary> /// Verifies that the values on the server are correct /// </summary> /// <param name="continuation">The async continuation</param> /// <param name="contextData">The context data</param> public void VerifyChangesOnServer(IAsyncContinuation continuation, DataServiceContextData contextData) { ExceptionUtilities.CheckArgumentNotNull(continuation, "continuation"); ExceptionUtilities.CheckArgumentNotNull(contextData, "contextData"); ExceptionUtilities.CheckAllRequiredDependencies(this); this.currentContextData = contextData; IEnumerable<ChangeData> expectedChanges; ExceptionUtilities.Assert(this.expectedChangeCache.TryGetValue(contextData, out expectedChanges), "Expected changes for given context have not been initialized"); this.expectedChangeCache.Remove(contextData); AsyncHelpers.AsyncForEach(expectedChanges, continuation, this.VerifyChangeOnServer); }
private static EntityDescriptorData GetTrackedEntityDescriptorData(DataServiceContextData data, object entity, string errorMessage, string argumentName) { ExceptionUtilities.CheckArgumentNotNull(data, "data"); EntityDescriptorData descriptorData; if (!data.TryGetEntityDescriptorData(entity, out descriptorData)) { throw new TaupoInvalidOperationException(errorMessage + " " + argumentName + " is not tracked by the data service context data."); } return descriptorData; }
private static void CheckEntityIsNotTracked(DataServiceContextData data, object entity) { ExceptionUtilities.CheckArgumentNotNull(data, "data"); EntityDescriptorData descriptorData; if (data.TryGetEntityDescriptorData(entity, out descriptorData)) { throw new TaupoInvalidOperationException( string.Format(CultureInfo.InvariantCulture, "Specified entity is already tracked by the descriptor data: {0}.", descriptorData.ToString())); } }
private static void CheckIdentity(DataServiceContextData data, Uri identity) { ExceptionUtilities.CheckArgumentNotNull(data, "data"); if (identity == null) { throw new TaupoInvalidOperationException("Entity identity cannot be null or empty."); } EntityDescriptorData descriptorData; if (data.TryGetEntityDescriptorData(identity, out descriptorData)) { throw new TaupoInvalidOperationException( string.Format(CultureInfo.InvariantCulture, "There is already an entity descriptor data with the specified identity: {0}.", descriptorData.ToString())); } }
private EntityInstance BuildEntityPayload( DataServiceContextData contextData, IDictionary<object, IEnumerable<NamedValue>> propertyValuesBeforeSave, EntityDescriptorData entityDescriptorData, DataServiceProtocolVersion dsv) { IEnumerable<NamedValue> propertyValues; ExceptionUtilities.Assert(propertyValuesBeforeSave.TryGetValue(entityDescriptorData.Entity, out propertyValues), "Could not find property values for descriptor: {0}", entityDescriptorData); var entityType = this.ModelSchema.EntityTypes.Single(t => t.FullName == entityDescriptorData.EntityClrType.FullName); var entityInstance = this.PayloadBuilder.EntityInstance(entityType, propertyValues); new ExpectedPayloadNormalizer(contextData, dsv).Normalize(entityInstance, entityDescriptorData); return entityInstance; }
/// <summary> /// Calculates the expected response from DataServiceContext.SaveChanges based on the context data before saving changes. /// Assumes there are no errors in the response. /// </summary> /// <param name="dataBeforeSaveChanges">The data before saving changes.</param> /// <param name="options">The options for saving changes.</param> /// <param name="context">The DataServiceContext instance which is calling SaveChanges.</param> /// <returns><see cref="DataServiceResponseData"/> that expresses expectations for the response.</returns> public DataServiceResponseData CalculateSaveChangesResponseData(DataServiceContextData dataBeforeSaveChanges, SaveChangesOptions options, DSClient.DataServiceContext context) { ExceptionUtilities.CheckArgumentNotNull(dataBeforeSaveChanges, "dataBeforeSaveChanges"); ExceptionUtilities.CheckArgumentNotNull(context, "context"); DataServiceResponseData responseData = new DataServiceResponseData(); responseData.IsBatchResponse = options == SaveChangesOptions.Batch; bool hasChanges = false; // Note: ordering is important as changes should be processed in the order specified by user. foreach (DescriptorData descriptorData in dataBeforeSaveChanges.GetOrderedChanges()) { int statusCode = (int)HttpStatusCode.NoContent; var entityDescriptorData = descriptorData as EntityDescriptorData; if (entityDescriptorData != null) { if (entityDescriptorData.IsMediaLinkEntry && entityDescriptorData.DefaultStreamState == EntityStates.Modified) { responseData.Add(new ChangeOperationResponseData(descriptorData) { StatusCode = statusCode }); } if (descriptorData.State == EntityStates.Added) { statusCode = GetStatusCodeForInsert(context); if (entityDescriptorData.IsMediaLinkEntry) { responseData.Add(new ChangeOperationResponseData(descriptorData) { StatusCode = statusCode }); statusCode = GetStatusCodeForUpdate(context); } } else if (descriptorData.State == EntityStates.Modified) { statusCode = GetStatusCodeForUpdate(context); } else if (descriptorData.State != EntityStates.Deleted) { continue; } } var linkDescriptorData = descriptorData as LinkDescriptorData; if (linkDescriptorData != null && (linkDescriptorData.State == EntityStates.Added || linkDescriptorData.State == EntityStates.Modified)) { if (!linkDescriptorData.WillTriggerSeparateRequest()) { continue; } } responseData.Add(new ChangeOperationResponseData(descriptorData) { StatusCode = statusCode }); hasChanges = true; } if (responseData.IsBatchResponse) { responseData.BatchStatusCode = hasChanges ? (int)HttpStatusCode.Accepted : 0; } else { responseData.BatchStatusCode = -1; } return responseData; }
/// <summary> /// Initializes a new instance of the ExpectedPayloadNormalizer class /// </summary> /// <param name="contextData">The context data</param> /// <param name="dsv">The data service version</param> public ExpectedPayloadNormalizer(DataServiceContextData contextData, DataServiceProtocolVersion dsv) { ExceptionUtilities.CheckArgumentNotNull(contextData, "contextData"); this.contextData = contextData; this.dsv = dsv; }
/// <summary> /// Calculates expected data for a request during DataServiceContext.SaveChanges for a particular descriptor. /// </summary> /// <param name="contextData">The context data</param> /// <param name="propertyValuesBeforeSave">The property values of the tracked client objects before the call to SaveChanges</param> /// <param name="descriptorData">The descriptor data</param> /// <param name="options">The save changes options</param> /// <returns>The expected client request</returns> public ExpectedClientRequest CalculateRequest(DataServiceContextData contextData, IDictionary<object, IEnumerable<NamedValue>> propertyValuesBeforeSave, DescriptorData descriptorData, SaveChangesOptions options) { ExceptionUtilities.CheckArgumentNotNull(contextData, "contextData"); ExceptionUtilities.CheckArgumentNotNull(descriptorData, "descriptorData"); ExceptionUtilities.CheckArgumentNotNull(propertyValuesBeforeSave, "propertyValuesBeforeSave"); var linkDescriptorData = descriptorData as LinkDescriptorData; var entityDescriptorData = descriptorData as EntityDescriptorData; var streamDescriptorData = descriptorData as StreamDescriptorData; ExpectedClientRequest request = null; if (linkDescriptorData != null) { if (linkDescriptorData.WillTriggerSeparateRequest()) { request = this.CreateLinkRequest(linkDescriptorData, options); } } else if (entityDescriptorData != null) { if (entityDescriptorData.State == EntityStates.Added) { request = this.CreateEntityInsertRequest(contextData, propertyValuesBeforeSave, entityDescriptorData, options); } else if (entityDescriptorData.State == EntityStates.Modified) { request = this.CreateEntityUpdateRequest(contextData, propertyValuesBeforeSave, entityDescriptorData, options); } else if (entityDescriptorData.State == EntityStates.Deleted) { request = this.CreateEntityDeleteRequest(entityDescriptorData, options); } } else if (streamDescriptorData != null) { if (streamDescriptorData.State == EntityStates.Added) { request = this.CreateStreamInsertRequest(contextData, streamDescriptorData, options); } else if (streamDescriptorData.State == EntityStates.Modified) { request = this.CreateStreamUpdateRequest(streamDescriptorData, options); } } if (request != null) { request.Headers[HttpHeaders.MaxDataServiceVersion] = ToClientHeaderFormat(contextData.MaxProtocolVersion); // perform sanity checks var missingHeaders = headersThatWillBeGenerated.Where(h => !request.Headers.ContainsKey(h)).ToArray(); ExceptionUtilities.Assert(missingHeaders.Length == 0, "Generated request was missing headers: {0}", string.Join(", ", missingHeaders)); ExceptionUtilities.CheckObjectNotNull(request.Uri, "Generated request was missing a Uri"); // sanity check: Client sends content-type header for delete request if (request.GetEffectiveVerb() == HttpVerb.Delete) { ExceptionUtilities.Assert( request.Headers[HttpHeaders.ContentType] == null, "Incorrect expectation: client should never send ContentType header for DELETE requests."); } } return request; }
/// <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 }
internal static Uri GetEntityInsertUri(DataServiceContextData contextData, EntityDescriptorData entityDescriptorData) { Uri insertUri; if (entityDescriptorData.InsertLink != null) { insertUri = entityDescriptorData.InsertLink; } else { ExceptionUtilities.CheckObjectNotNull(entityDescriptorData.ParentForInsert, "Entity descriptor data did not have insert link or parent for insert: {0}", entityDescriptorData); ExceptionUtilities.CheckObjectNotNull(entityDescriptorData.ParentPropertyForInsert, "Entity descriptor data did not have insert link or parent property for insert: {0}", entityDescriptorData); var parentDescriptor = contextData.GetEntityDescriptorData(entityDescriptorData.ParentForInsert); var linkInfo = parentDescriptor.LinkInfos.SingleOrDefault(l => l.Name == entityDescriptorData.ParentPropertyForInsert); if (linkInfo != null && linkInfo.NavigationLink != null) { insertUri = linkInfo.NavigationLink; } else { insertUri = new Uri(UriHelpers.ConcatenateUriSegments(parentDescriptor.EditLink.OriginalString, entityDescriptorData.ParentPropertyForInsert), UriKind.RelativeOrAbsolute); if (!insertUri.IsAbsoluteUri && contextData.BaseUri != null) { insertUri = new Uri(contextData.BaseUri, insertUri); } } } return insertUri; }
/// <summary> /// Executes SaveChanges on the specified context and with the default 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> /// <returns>The response from SaveChanges</returns> public static DSClient.DataServiceResponse VerifySaveChanges(this ISaveChangesVerifier verifier, DataServiceContextData contextData, DSClient.DataServiceContext context) { ExceptionUtilities.CheckArgumentNotNull(verifier, "verifier"); ExceptionUtilities.CheckArgumentNotNull(contextData, "contextData"); ExceptionUtilities.CheckArgumentNotNull(context, "context"); return(verifier.VerifySaveChanges(contextData, context, null)); }
private ExpectedClientRequest CreateEntityInsertRequest(DataServiceContextData contextData, IDictionary<object, IEnumerable<NamedValue>> propertyValuesBeforeSave, EntityDescriptorData entityDescriptorData, SaveChangesOptions options) { ExceptionUtilities.Assert(!entityDescriptorData.IsMediaLinkEntry, "Can only be used for non media-link-entries"); var insertUri = GetEntityInsertUri(contextData, entityDescriptorData); ExpectedClientRequest request = new ExpectedClientRequest() { Verb = HttpVerb.Post, Uri = insertUri }; string preference = contextData.AddAndUpdateResponsePreference.ToHeaderValue(); DataServiceProtocolVersion dsv = GetDataServiceVersion(HttpVerb.Post, preference); dsv = dsv.IncreaseVersionIfRequired(this.VersionCalculator.CalculateDataServiceVersion(entityDescriptorData, contextData.MaxProtocolVersion)); var payload = this.BuildEntityPayload(contextData, propertyValuesBeforeSave, entityDescriptorData, dsv); request.Body = payload; this.AddFoldedLinksToEntityInsertPayload(contextData, entityDescriptorData, payload); request.Headers[HttpHeaders.DataServiceVersion] = ToClientHeaderFormat(dsv); request.Headers[HttpHeaders.IfMatch] = null; request.Headers[HttpHeaders.Prefer] = preference; this.SetDefaultAcceptHeader(request, options); this.SetContentTypeHeaderForEntity(request); string hintString = @"Entity insert\r\n{{\r\n Descriptor = {0}\r\n Options = {1}\r\n}}"; request.DebugHintString = string.Format(CultureInfo.InvariantCulture, hintString, entityDescriptorData, options); return request; }
/// <summary> /// Executes SaveChanges on the specified context and verifies the results. /// </summary> /// <param name="verifier">The verifier to use for verification.</param> /// <param name="continuation">The asynchronous continuation</param> /// <param name="context">The context to verify SaveChanges on.</param> /// <param name="options">The options to use, or null for the default</param> /// <param name="onCompletion">The callback to call on completion</param> public static void VerifySaveChanges(this ISaveChangesVerifier verifier, IAsyncContinuation continuation, WrappedDataServiceContext context, SaveChangesOptions?options, Action <IAsyncContinuation, DSClient.DataServiceResponse> onCompletion) { DataServiceContextData data = CheckParametersAndGetDataServiceContextData(verifier, context); verifier.VerifySaveChanges(continuation, data, (DSClient.DataServiceContext)context.Product, options, onCompletion); }
/// <summary> /// Initializes a new instance of the PipelineEmulator class /// </summary> /// <param name="parent">The parent instance to get dependencies from</param> /// <param name="contextData">The current context data</param> /// <param name="propertyValuesBeforeSave">The property values of the tracked client objects before the call to SaveChanges</param> /// <param name="options">The current save-changes options</param> /// <param name="requestResponsePairs">The observed http traffic for the current save-changes call</param> public PipelineEmulator(SaveChangesHttpValidatingEmulator parent, DataServiceContextData contextData, IDictionary<object, IEnumerable<NamedValue>> propertyValuesBeforeSave, SaveChangesOptions options, IEnumerable<KeyValuePair<IHttpRequest, HttpResponseData>> requestResponsePairs) { this.parent = parent; this.contextData = contextData; this.propertyValuesBeforeSave = propertyValuesBeforeSave; this.options = options; this.httpQueue = new Queue<KeyValuePair<IHttpRequest, HttpResponseData>>(requestResponsePairs); }