/// <summary>
            /// Gets the URI for requery.
            /// </summary>
            /// <returns>Uri for requery.</returns>
            public override Uri GetUriForRequery()
            {
                LinkDescriptorData linkData = this.DescriptorData;

                Uri uri      = null;
                var linkInfo = linkData.SourceDescriptor.LinkInfos.SingleOrDefault(l => l.Name == linkData.SourcePropertyName);

                if (linkInfo != null)
                {
                    uri = linkInfo.NavigationLink;
                }

                if (uri == null)
                {
                    uri = new Uri(linkData.SourceDescriptor.EditLink + "/" + linkData.SourcePropertyName);
                }

                if (!this.IsReference)
                {
                    ExceptionUtilities.Assert(linkData.TargetDescriptor != null, "TargetDescriptor can not be null for the link descriptor representing collection.");
                    ExceptionUtilities.CheckObjectNotNull(linkData.TargetDescriptor.EditLink, "Target edit-link can not be null for the link descriptor representing collection.");

                    Regex keyRegex = new Regex(@".+(?<key>\(.+\))");
                    Match match    = keyRegex.Match(linkData.TargetDescriptor.EditLink.OriginalString);
                    ExceptionUtilities.Assert(match.Success, "Unhandled entity edit-link format. Edit link: " + linkData.TargetDescriptor.EditLink);

                    string targetKey = match.Groups["key"].Value;
                    uri = new Uri(uri + targetKey);
                }

                return(uri);
            }
 private HttpRequestData CreateAddLinkRequest(LinkDescriptorData linkDescriptorData, LinkInfoData info)
 {
     return(new HttpRequestData()
     {
         Uri = this.GetLinkUri(linkDescriptorData, info), Verb = HttpVerb.Post
     });
 }
        private HttpRequestData CreateDeleteLinkRequest(LinkDescriptorData linkDescriptorData, LinkInfoData info)
        {
            string keyString = this.EntityDescriptorValueCalculator.CalculateEntityKey(linkDescriptorData.TargetDescriptor.Entity);

            return(new HttpRequestData()
            {
                Uri = new Uri(this.GetLinkUri(linkDescriptorData, info).OriginalString + keyString), Verb = HttpVerb.Delete
            });
        }
Beispiel #4
0
        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
            }
        }
        internal static Uri BuildLinkUri(LinkDescriptorData linkDescriptorData, LinkInfoData info)
        {
            Uri linkUri;

            if (info != null && info.RelationshipLink != null)
            {
                linkUri = info.RelationshipLink;
            }
            else
            {
                ExceptionUtilities.CheckObjectNotNull(linkDescriptorData.SourceDescriptor.EditLink, "Edit link of source descriptor cannot be null");
                linkUri = new Uri(UriHelpers.ConcatenateUriSegments(linkDescriptorData.SourceDescriptor.EditLink.OriginalString, Endpoints.Ref, linkDescriptorData.SourcePropertyName), UriKind.RelativeOrAbsolute);
            }

            return(linkUri);
        }
        private HttpRequestData CreateSetLinkRequest(LinkDescriptorData linkDescriptorData, LinkInfoData info)
        {
            HttpVerb verb;

            if (linkDescriptorData.TargetDescriptor == null)
            {
                verb = HttpVerb.Delete;
            }
            else
            {
                verb = HttpVerb.Put;
            }

            return(new HttpRequestData()
            {
                Uri = this.GetLinkUri(linkDescriptorData, info), Verb = verb
            });
        }
            private LinkDescriptor GetLinkDescriptor(LinkDescriptorData linkDescriptorData)
            {
                object sourceEntity = this.GetEntityDescriptor(linkDescriptorData.SourceDescriptor).Entity;

                object targetEntity = linkDescriptorData.TargetDescriptor != null?
                                      this.GetEntityDescriptor(linkDescriptorData.TargetDescriptor).Entity : null;

                // Note: GetLinkDescriptor throws ArgumenNullException when target is null even so there is an existing link with null target.
                var descriptor = targetEntity != null?
                                 this.context.GetLinkDescriptor(sourceEntity, linkDescriptorData.SourcePropertyName, targetEntity)
                                     : this.context.Links.Where(l => l.Source == sourceEntity && l.SourceProperty == linkDescriptorData.SourcePropertyName && l.Target == null).SingleOrDefault();

                if (descriptor == null)
                {
                    throw new AssertionFailedException(
                              string.Format(CultureInfo.InvariantCulture, "Link descriptor is missing from the data service context. Expected link descriptor data: {{{0}}}.", linkDescriptorData));
                }

                return(descriptor);
            }
Beispiel #8
0
        /// <summary>
        /// Tracks the SetLink method.
        /// </summary>
        /// <param name="data">The data service context data on which to apply state transition.</param>
        /// <param name="source">The source.</param>
        /// <param name="sourcePropertyName">Name of the source property.</param>
        /// <param name="target">The target.</param>
        public static void TrackSetLink(this DataServiceContextData data, object source, string sourcePropertyName, object target)
        {
            ExceptionUtilities.CheckStringArgumentIsNotNullOrEmpty(sourcePropertyName, "sourcePropertyName");

            EntityDescriptorData sourceDescriptorData = GetTrackedEntityDescriptorData(data, source, "Cannot set link:", "source");

            CheckStateIsNot(EntityStates.Deleted, sourceDescriptorData, "Cannot set link:", "source");

            EntityDescriptorData targetDescriptorData = null;

            if (target != null)
            {
                targetDescriptorData = GetTrackedEntityDescriptorData(data, target, "Cannot set link:", "target");
                CheckStateIsNot(EntityStates.Deleted, sourceDescriptorData, "Cannot set link:", "target");
            }

            var relatedToSource = data.LinkDescriptorsData.Where(e => e.SourceDescriptor.Entity == source && e.SourcePropertyName == sourcePropertyName).ToList();

            if (relatedToSource.Count > 1)
            {
                throw new TaupoInvalidOperationException("Cannot set link: source contains multiple links for the property: " + sourcePropertyName);
            }

            LinkDescriptorData existingLinkDescriptorData = relatedToSource.FirstOrDefault();

            if (existingLinkDescriptorData == null)
            {
                data.CreateLinkDescriptorData(EntityStates.Modified, data.GetNextChangeOrder(), sourceDescriptorData, sourcePropertyName, targetDescriptorData);
            }
            else
            {
                if (existingLinkDescriptorData.State != EntityStates.Modified || existingLinkDescriptorData.TargetDescriptor != targetDescriptorData)
                {
                    data.ChangeStateAndChangeOrder(existingLinkDescriptorData, EntityStates.Modified, data.GetNextChangeOrder());
                }

                existingLinkDescriptorData.TargetDescriptor = targetDescriptorData;
            }
        }
            /// <summary>
            /// Creates LinkChangeData which captures the state of the specified link descriptor data.
            /// </summary>
            /// <param name="linkData">The link descriptor data.</param>
            /// <returns>Link change data.</returns>
            public static LinkChangeData Create(LinkDescriptorData linkData)
            {
                ExceptionUtilities.CheckArgumentNotNull(linkData, "linkData");

                LinkChangeData changeData = new LinkChangeData(linkData);

                var isEnumerable = linkData.SourceDescriptor.EntityClrType.GetProperty(linkData.SourcePropertyName).PropertyType.GetInterfaces().Any(t => t.Name == "IEnumerable");

                changeData.IsReference = !isEnumerable;

                if (linkData.TargetDescriptor != null)
                {
                    changeData.ClrTypeForRequery = linkData.TargetDescriptor.EntityClrType;
                }
                else
                {
                    ExceptionUtilities.Assert(changeData.IsReference, "TargetDescriptor can not be null for the link descriptor representing collection.");
                    changeData.ClrTypeForRequery = linkData.SourceDescriptor.EntityClrType.GetProperty(linkData.SourcePropertyName).PropertyType;
                }

                return(changeData);
            }
        private ExpectedClientRequest CreateLinkRequest(LinkDescriptorData linkDescriptorData, SaveChangesOptions options)
        {
            var info = linkDescriptorData.SourceDescriptor.LinkInfos.SingleOrDefault(l => l.Name == linkDescriptorData.SourcePropertyName);
            ExpectedClientRequest request = new ExpectedClientRequest()
            {
                Uri = BuildLinkUri(linkDescriptorData, info)
            };

            if (linkDescriptorData.State == EntityStates.Added)
            {
                request.Verb = HttpVerb.Post;

                // 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
                request.Body = new DeferredLink()
                {
                    UriString = linkDescriptorData.TargetDescriptor.EditLink.OriginalString
                };
            }
            else if (linkDescriptorData.State == EntityStates.Modified)
            {
                if (linkDescriptorData.TargetDescriptor == null)
                {
                    request.Verb = HttpVerb.Delete;
                }
                else
                {
                    request.Verb = HttpVerb.Put;

                    // 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
                    request.Body = new DeferredLink()
                    {
                        UriString = linkDescriptorData.TargetDescriptor.EditLink.OriginalString
                    };
                }
            }
            else
            {
                ExceptionUtilities.Assert(linkDescriptorData.State == EntityStates.Deleted, "Link descriptor was in unexpected state '{0}'", linkDescriptorData.State);

                string keyString = this.EntityDescriptorValueCalculator.CalculateEntityKey(linkDescriptorData.TargetDescriptor.Entity);
                request.Uri  = new Uri(request.Uri.OriginalString + keyString);
                request.Verb = HttpVerb.Delete;
            }

            request.Headers[HttpHeaders.IfMatch]            = null;
            request.Headers[HttpHeaders.Prefer]             = null;
            request.Headers[HttpHeaders.DataServiceVersion] = ToClientHeaderFormat(DataServiceProtocolVersion.V4);

            this.SetDefaultAcceptHeader(request, options);

            if (request.Verb != HttpVerb.Delete)
            {
                request.Headers[HttpHeaders.ContentType] = string.IsNullOrWhiteSpace(this.ClientRequestAcceptHeader) ? MimeTypes.ApplicationXml : this.ClientRequestAcceptHeader;
            }
            else
            {
                request.Headers[HttpHeaders.ContentType] = null;
            }

            string hintString = @"Link\r\n{{\r\n  Descriptor = {0}\r\n  Options = {1}\r\n}}";

            request.DebugHintString = string.Format(CultureInfo.InvariantCulture, hintString, linkDescriptorData, options);

            return(request);
        }
Beispiel #11
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;
                }
            }
        }
 /// <summary>
 /// Initializes a new instance of the <see cref="LinkChangeData"/> class.
 /// </summary>
 /// <param name="linkDescriptorData">The link descriptor data.</param>
 protected LinkChangeData(LinkDescriptorData linkDescriptorData)
     : base(linkDescriptorData)
 {
 }