示例#1
0
        /// <summary>Creates a many-to-one or one-to-one relationship between two objects in the object context.</summary>
        /// <param name="entity">The object being attached.</param>
        /// <exception cref="T:System.ArgumentNullException">When the  entity  is null.</exception>
        /// <exception cref="T:System.InvalidOperationException">When the  entity  cannot be related to the current related end. This can occur when the association in the conceptual schema does not support a relationship between the two types.</exception>
        public void Attach(TEntity entity)
        {
            Check.NotNull(entity, "entity");

            CheckOwnerNull();
            Attach(new[] { EntityWrapperFactory.WrapEntityUsingContext(entity, ObjectContext) }, false);
        }
示例#2
0
        public void DoWork(IRequest request)
        {
            if (String.IsNullOrEmpty(_requestContext.ResourceKey))
            {
                throw new RequestException("Please use single resource url");
            }


            IEntityWrapper wrapper;

            wrapper = EntityWrapperFactory.Create(_requestContext.ResourceKind, _requestContext);

            SdataTransactionResult sdTrResult = wrapper.Delete(_requestContext.ResourceKey);

            if (sdTrResult == null)
            {
                throw new RequestException("Entity does not exists");
            }

            if (sdTrResult.HttpStatus == System.Net.HttpStatusCode.OK)
            {
                request.Response.StatusCode = System.Net.HttpStatusCode.OK;
            }
            else
            {
                throw new RequestException(sdTrResult.HttpMessage);
            }
        }
示例#3
0
        public void DoWork(IRequest request)
        {
            if (request.ContentType != Sage.Common.Syndication.MediaType.AtomEntry)
            {
                throw new RequestException("Atom entry content type expected");
            }

            if (!String.IsNullOrEmpty(_requestContext.ResourceKey))
            {
                throw new RequestException("Please use resource url");
            }

            // read entry from stream
            SyncFeedEntry entry  = new SyncFeedEntry();
            XmlReader     reader = XmlReader.Create(request.Stream);

            reader.MoveToContent();

            entry.ReadXml(reader, ResourceKindHelpers.GetPayloadType(_requestContext.ResourceKind));

            IEntityWrapper wrapper = EntityWrapperFactory.Create(_requestContext.ResourceKind, _requestContext);


            Document document = wrapper.GetTransformedDocument(entry.Payload, entry.SyncLinks);

            if (!String.IsNullOrEmpty(document.Id))
            {
                throw new RequestException("Entity alredy exists");
            }

            // Add Document

            SdataTransactionResult sdTrResult = wrapper.Add(entry.Payload, entry.SyncLinks);

            if (sdTrResult == null)
            {
                throw new RequestException("Entity does not exists"); //?????
            }
            if ((sdTrResult.HttpStatus == System.Net.HttpStatusCode.OK) ||
                (sdTrResult.HttpStatus == System.Net.HttpStatusCode.Created))
            {
                // store correlation
                SyncFeedEntry responseEntry = wrapper.GetFeedEntry(sdTrResult.LocalId);

                SyncFeed feed = new SyncFeed();
                feed.FeedType = FeedType.ResourceEntry;
                feed.Entries.Add(responseEntry);
                request.Response.StatusCode = System.Net.HttpStatusCode.Created;
                request.Response.Serializer = new SyncFeedSerializer();
                request.Response.Feed       = feed;
                request.Response.Protocol.SendUnknownResponseHeader("Location", responseEntry.Id);
                request.Response.ContentType = Sage.Common.Syndication.MediaType.AtomEntry;
            }
            else
            {
                throw new RequestException(sdTrResult.HttpMessage);
            }
        }
示例#4
0
        /// <summary>Defines relationships between an object and a collection of related objects in an object context.</summary>
        /// <remarks>
        /// Loads related entities into the local collection. If the collection is already filled
        /// or partially filled, merges existing entities with the given entities. The given
        /// entities are not assumed to be the complete set of related entities.
        /// Owner and all entities passed in must be in Unchanged or Modified state. We allow
        /// deleted elements only when the state manager is already tracking the relationship
        /// instance.
        /// </remarks>
        /// <param name="entities">Collection of objects in the object context that are related to the source object.</param>
        /// <exception cref="T:System.ArgumentNullException"> entities  collection is null.</exception>
        /// <exception cref="T:System.InvalidOperationException">
        /// The source object or an object in the  entities  collection is null or is not in an
        /// <see
        ///     cref="F:System.Data.Entity.EntityState.Unchanged" />
        /// or <see cref="F:System.Data.Entity.EntityState.Modified" /> state.-or-The relationship cannot be defined based on the EDM metadata. This can occur when the association in the conceptual schema does not support a relationship between the two types.
        /// </exception>
        public void Attach(IEnumerable <TEntity> entities)
        {
            Check.NotNull(entities, "entities");
            CheckOwnerNull();
            IList <IEntityWrapper> wrappedEntities = new List <IEntityWrapper>();

            foreach (var entity in entities)
            {
                wrappedEntities.Add(EntityWrapperFactory.WrapEntityUsingContext(entity, ObjectContext));
            }
            Attach(wrappedEntities, true);
        }
示例#5
0
 public void OnCollectionDeserialized(StreamingContext context)
 {
     if (_relatedEntities != null)
     {
         // We need to call this here so that the hash set will be fully constructed
         // ready for access.  Normally, this would happen later in the process.
         _relatedEntities.OnDeserialization(null);
         _wrappedRelatedEntities = new Dictionary <TEntity, IEntityWrapper>();
         foreach (TEntity entity in _relatedEntities)
         {
             _wrappedRelatedEntities.Add(entity, EntityWrapperFactory.WrapEntityUsingContext(entity, ObjectContext));
         }
     }
 }
示例#6
0
 internal override void Include(bool addRelationshipAsUnchanged, bool doAttach)
 {
     if (null != _wrappedRelatedEntities && null != this.ObjectContext)
     {
         List <IEntityWrapper> wrappedRelatedEntities = new List <IEntityWrapper>(_wrappedRelatedEntities.Values);
         foreach (IEntityWrapper wrappedEntity in wrappedRelatedEntities)
         {
             // Sometimes with mixed POCO and IPOCO, you can get different instances of IEntityWrappers stored in the IPOCO related ends
             // These should be replaced by the IEntityWrapper that is stored in the context
             IEntityWrapper identityWrapper = EntityWrapperFactory.WrapEntityUsingContext(wrappedEntity.Entity, WrappedOwner.Context);
             if (identityWrapper != wrappedEntity)
             {
                 _wrappedRelatedEntities[(TEntity)identityWrapper.Entity] = identityWrapper;
             }
             IncludeEntity(identityWrapper, addRelationshipAsUnchanged, doAttach);
         }
     }
 }
示例#7
0
        public void DoWork(IRequest request)
        {
            IEntityWrapper wrapper  = EntityWrapperFactory.Create(_requestContext.ResourceKind, _requestContext);
            SyncFeed       syncFeed = wrapper.GetFeed();

            request.Response.Serializer = new SyncFeedSerializer();

            if (String.IsNullOrEmpty(_requestContext.ResourceKey))
            {
                syncFeed.FeedType            = FeedType.Resource;
                request.Response.ContentType = Sage.Common.Syndication.MediaType.Atom;
            }
            else
            {
                syncFeed.FeedType            = FeedType.ResourceEntry;
                request.Response.ContentType = Sage.Common.Syndication.MediaType.AtomEntry;
            }
            request.Response.Feed = syncFeed;
        }
        internal override void Include(bool addRelationshipAsUnchanged, bool doAttach)
        {
            Debug.Assert(this.ObjectContext != null, "Should not be trying to add entities to state manager if context is null");

            // If we have an actual value or a key for this reference, add it to the context
            if (null != _wrappedCachedValue.Entity)
            {
                // Sometimes with mixed POCO and IPOCO, you can get different instances of IEntityWrappers stored in the IPOCO related ends
                // These should be replaced by the IEntityWrapper that is stored in the context
                IEntityWrapper identityWrapper = EntityWrapperFactory.WrapEntityUsingContext(_wrappedCachedValue.Entity, WrappedOwner.Context);
                if (identityWrapper != _wrappedCachedValue)
                {
                    _wrappedCachedValue = identityWrapper;
                }
                IncludeEntity(_wrappedCachedValue, addRelationshipAsUnchanged, doAttach);
            }
            else if (DetachedEntityKey != null)
            {
                IncludeEntityKey(doAttach);
            }
            // else there is nothing to add for this relationship
        }
 public void OnRefDeserialized(StreamingContext context)
 {
     _wrappedCachedValue = EntityWrapperFactory.WrapEntityUsingContext(_cachedValue, ObjectContext);
 }
 /// <summary>
 /// Attaches an entity to the EntityReference. The given
 /// entity is not assumed to be the complete set of related entities.
 ///
 /// Owner and all entities passed in must be in Unchanged or Modified state.
 /// Deleted elements are allowed only when the state manager is already tracking the relationship
 /// instance.
 /// </summary>
 /// <param name="entity">The entity to attach to the EntityCollection</param>
 /// <exception cref="ArgumentNullException">Thrown when <paramref name="entity"/> is null.</exception>
 /// <exception cref="InvalidOperationException">Thrown when the entity cannot be related via the current relationship end.</exception>
 public void Attach(TEntity entity)
 {
     CheckOwnerNull();
     EntityUtil.CheckArgumentNull(entity, "entity");
     Attach(new IEntityWrapper[] { EntityWrapperFactory.WrapEntityUsingContext(entity, ObjectContext) }, false);
 }
示例#11
0
 internal bool RemoveInternal(TEntity entity)
 {
     return(Remove(EntityWrapperFactory.WrapEntityUsingContext(entity, ObjectContext), /*preserveForeignKey*/ false));
 }
示例#12
0
        /// <summary>Adds an object to the collection.</summary>
        /// <param name="item">
        /// An object to add to the collection.  entity  must implement
        /// <see
        ///     cref="T:System.Data.Entity.Core.Objects.DataClasses.IEntityWithRelationships" />
        /// .
        /// </param>
        /// <exception cref="T:System.ArgumentNullException"> entity  is null.</exception>
        public void Add(TEntity item)
        {
            Check.NotNull(item, "item");

            Add(EntityWrapperFactory.WrapEntityUsingContext(item, ObjectContext));
        }
            // Asynchronous called method
            private void Execute(NorthwindConfig config, SyncFeed feed)
            {
                #region Declarations

                SdataContext                sdataContext;
                SupportedResourceKinds      resource;
                IAppBookmarkInfoStore       appBookmarkInfoStore;
                ICorrelatedResSyncInfoStore correlatedResSyncInfoStore;
                ISyncSyncDigestInfoStore    syncDigestStore;

                GuidConverter  guidConverter = new GuidConverter();
                string         resourceKind;
                string         endpoint;
                SyncFeedDigest sourceDigest;
                SyncDigestInfo targetDigest;

                IEntityWrapper wrapper;

                #endregion

                #region init

                sdataContext               = _parentPerformer._requestContext.SdataContext;
                resource                   = _parentPerformer._requestContext.ResourceKind;
                resourceKind               = resource.ToString();
                endpoint                   = _parentPerformer._requestContext.DatasetLink + resourceKind;
                appBookmarkInfoStore       = RequestReceiver.NorthwindAdapter.StoreLocator.GetAppBookmarkStore(sdataContext);
                correlatedResSyncInfoStore = RequestReceiver.NorthwindAdapter.StoreLocator.GetCorrelatedResSyncStore(sdataContext);
                syncDigestStore            = RequestReceiver.NorthwindAdapter.StoreLocator.GetSyncDigestStore(sdataContext);
                sourceDigest               = feed.Digest;
                targetDigest               = syncDigestStore.Get(resourceKind);
                wrapper = EntityWrapperFactory.Create(resource, _parentPerformer._requestContext);

                #endregion

                #region process entries

                bool sourceIsDeleteMode;
                SdataTransactionResult sdTrResult;
                SyncState sourceState;
                SyncState targetState;

                foreach (SyncFeedEntry entry in feed.Entries)
                {
                    sdTrResult = null;

                    try
                    {
                        // Check whether the source entry had been deleted.
                        // if not we expect a payload!
                        // The variable 'sourceIsDeleteMode' holds the result of this check for later calls.
                        if (entry.HttpMethod.Equals("DELETE", StringComparison.InvariantCultureIgnoreCase))
                        {
                            sourceIsDeleteMode = true;
                        }
                        else if (null == entry.Payload)
                        {
                            throw new Exception("Payload missing.");
                        }
                        else
                        {
                            sourceIsDeleteMode = false;
                        }


                        // set the uuid to the payload.SyncUuid property
                        if (!sourceIsDeleteMode)
                        {
                            entry.Payload.SyncUuid = entry.Uuid;
                        }

                        // get the source syncstate
                        sourceState = entry.SyncState;

                        // Look into the store to get all correlations of the uuid received from source
                        CorrelatedResSyncInfo[] corelations = correlatedResSyncInfoStore.GetByUuid(resourceKind, new Guid[] { entry.Uuid });

                        if (corelations.Length == 0)
                        {
                            if (sourceIsDeleteMode)
                            {
                                // the source entry had been deleted and no correlation exists for this
                                // entry in the target.
                                // So we do nothing here.
                                sdTrResult              = new SdataTransactionResult();
                                sdTrResult.HttpStatus   = HttpStatusCode.OK;
                                sdTrResult.HttpMessage  = "OK";
                                sdTrResult.HttpMethod   = "DELETE";
                                sdTrResult.ResourceKind = resource;
                                sdTrResult.Uuid         = entry.Uuid;
                            }
                            else
                            {
                                // no target entry exists for the updated or added source entry.
                                // So we add the source entry to the application and add a new correlation to the sync store.
                                // If this operation fails we will have to set the result state to conflict.
                                try
                                {
                                    // add the entry to application
                                    sdTrResult = wrapper.Add(entry.Payload, entry.SyncLinks);

                                    if ((sdTrResult != null) && ((sdTrResult.HttpStatus == HttpStatusCode.OK) || (sdTrResult.HttpStatus == HttpStatusCode.Created)))
                                    {
                                        string etag = EtagServices.ComputeEtag(entry.Payload, true);

                                        ResSyncInfo resSyncInfo =
                                            new ResSyncInfo(entry.Uuid, entry.SyncState.Endpoint,
                                                            entry.SyncState.Tick, etag, entry.SyncState.Stamp);

                                        CorrelatedResSyncInfo correlatedResSyncInfo = new CorrelatedResSyncInfo(sdTrResult.LocalId, resSyncInfo);

                                        // store the new correlation to the sync store
                                        correlatedResSyncInfoStore.Put(resourceKind, correlatedResSyncInfo);
                                        // update the sync digest entry if the tick of the source entry is newer than the actual tick of the target.
                                        syncDigestStore.PersistNewer(resourceKind, correlatedResSyncInfo.ResSyncInfo);
                                    }
                                }
                                catch (Exception e)
                                {
                                    // in case of an unexpected error while adding a new entry to target
                                    // we create a transaction result with the state 'Conflict'
                                    sdTrResult              = new SdataTransactionResult();
                                    sdTrResult.HttpStatus   = HttpStatusCode.Conflict;
                                    sdTrResult.HttpMethod   = "POST";
                                    sdTrResult.HttpMessage  = e.ToString();
                                    sdTrResult.ResourceKind = resource;
                                    sdTrResult.Uuid         = entry.Uuid;
                                }
                            }
                        }
                        else
                        {
                            // a correlation was found for the source entry.

                            #region update or delete

                            try
                            {
                                bool doUpdate = false;
                                //bool doDelete = false;
                                bool isConflict = true;

                                // set the LocalID from correlation to the entry.Payload.LocalID property
                                // only if source had not been deleted.
                                if (!sourceIsDeleteMode)
                                {
                                    entry.Payload.LocalID = corelations[0].LocalId;
                                }

                                targetState = Helper.GetSyncState(corelations[0]);


                                //If sourceState.endpoint = targetState.endpoint,
                                //there is no conflict and the update must be applied
                                //if sourceState.tick > targetState.tick.
                                if (targetState.Endpoint.Equals(sourceState.Endpoint, StringComparison.InvariantCultureIgnoreCase))
                                {
                                    isConflict = false;
                                    if (sourceState.Tick > targetState.Tick)
                                    {
                                        //if (!sourceIsDeleteMode)
                                        doUpdate = true;
                                        //else
                                        //    doDelete = true;
                                    }
                                }
                                else
                                {
                                    SyncState sourceDigestSyncState = Helper.GetSyncState(sourceDigest, targetState.Endpoint);;
                                    SyncState targetDigestSyncState = Helper.GetSyncState(targetDigest, sourceState.Endpoint);

                                    //If targetState is contained in sourceDigest,
                                    //i.e. if sourceDigest has a digest entry E such that E.endpoint = targetState.endpoint
                                    //and E.tick >= targetState.tick, there is no conflict and the update must be applied.
                                    if (sourceDigestSyncState != null)
                                    {
                                        if (sourceDigestSyncState.Tick > targetState.Tick)
                                        {
                                            doUpdate   = true;
                                            isConflict = false;
                                        }
                                    }


                                    //If sourceState is contained in targetDigest,
                                    //i.e. if targetDigest has a digest entry E such that E.endpoint = sourceState.endpoint
                                    //and E.tick >= sourceState.tick, there is no conflict and the update must be ignored
                                    //(target has the most recent version).
                                    if (targetDigestSyncState != null)
                                    {
                                        if (targetDigestSyncState.Tick > sourceState.Tick)
                                        {
                                            doUpdate   = false;
                                            isConflict = false;
                                        }
                                    }



                                    //Otherwise (targetState not contained in sourceDigest, sourceState not contained in targetDigest),
                                    //there is a conflict.
                                    if ((sourceDigestSyncState == null) && (targetDigestSyncState == null))
                                    {
                                        isConflict = true;
                                    }
                                }

                                //****************** Conflict ****************
                                //In case of conflict, the target endpoint uses the following algorithm to resolve the conflict:
                                //Let sourceEntry be the sourceDigest digest entry such that sourceEntry.endpoint = sourceState.endpoint.
                                //Let targetEntry be the targetDigest digest entry such that targetEntry.endpoint = targetState.endpoint.
                                //If sourceEntry .conflictPriority <> targetEntry .conflictPriority, the side with lowest priority wins.
                                if (isConflict)
                                {
                                    int sourceConflictPriority = Helper.GetConflictPriority(sourceDigest, sourceState.Endpoint);
                                    int targetConflictPriority = Helper.GetConflictPriority(targetDigest, targetState.Endpoint);

                                    if (sourceConflictPriority > targetConflictPriority)
                                    {
                                        doUpdate = true;
                                    }
                                    else if (sourceConflictPriority < targetConflictPriority)
                                    {
                                        doUpdate = false;
                                    }
                                    else
                                    {
                                        //Otherwise (sourceEntry .conflictPriority = targetEntry .conflictPriority),
                                        //then sourceState.stamp and targetState.stamp are compared
                                        //and the entry with the most recent timestamp wins.
                                        if (sourceState.Stamp > targetState.Stamp)
                                        {
                                            doUpdate = true;
                                        }
                                    }
                                }
                                ResSyncInfo resSyncInfo =
                                    new ResSyncInfo(entry.Uuid, entry.SyncState.Endpoint,
                                                    entry.SyncState.Tick, "", entry.SyncState.Stamp);


                                if (doUpdate && !sourceIsDeleteMode)
                                {
                                    // update the entry in the application and update the sync store
                                    sdTrResult = wrapper.Update(entry.Payload, entry.SyncLinks);

                                    if ((sdTrResult != null) && (sdTrResult.HttpStatus == HttpStatusCode.OK))
                                    {
                                        string etag = EtagServices.ComputeEtag(entry.Payload, true);

                                        resSyncInfo =
                                            new ResSyncInfo(entry.Uuid, entry.SyncState.Endpoint,
                                                            entry.SyncState.Tick, etag, entry.SyncState.Stamp);

                                        CorrelatedResSyncInfo correlatedResSyncInfo = new CorrelatedResSyncInfo(sdTrResult.LocalId, resSyncInfo);

                                        correlatedResSyncInfoStore.Put(resourceKind, correlatedResSyncInfo);
                                    }
                                }
                                else if (!doUpdate && !sourceIsDeleteMode)
                                {
                                    sdTrResult              = new SdataTransactionResult();
                                    sdTrResult.HttpStatus   = HttpStatusCode.Conflict;
                                    sdTrResult.HttpMethod   = "PUT";
                                    sdTrResult.HttpMessage  = "";
                                    sdTrResult.ResourceKind = resource;
                                    sdTrResult.Uuid         = entry.Uuid;
                                }
                                else if (doUpdate && sourceIsDeleteMode)
                                {
                                    // delete the entry in the application and update the sync store
                                    // we do not support nested deletion. So only TradingAccounts and SalesOrders can be deleted.
                                    if (resource == SupportedResourceKinds.tradingAccounts ||
                                        resource == SupportedResourceKinds.salesOrders)
                                    {
                                        sdTrResult = wrapper.Delete(corelations[0].LocalId);

                                        if ((sdTrResult != null) && (sdTrResult.HttpStatus == HttpStatusCode.OK))
                                        {
                                            correlatedResSyncInfoStore.Delete(resource.ToString(), corelations[0].ResSyncInfo.Uuid);
                                        }
                                    }
                                    else
                                    {
                                        // this  does not correspond to real fact, what we did at target side!
                                        sdTrResult              = new SdataTransactionResult();
                                        sdTrResult.HttpStatus   = HttpStatusCode.OK;
                                        sdTrResult.HttpMessage  = "OK";
                                        sdTrResult.HttpMethod   = "DELETE";
                                        sdTrResult.ResourceKind = resource;
                                        sdTrResult.Uuid         = entry.Uuid;
                                    }
                                }
                                else
                                {
                                    sdTrResult              = new SdataTransactionResult();
                                    sdTrResult.HttpStatus   = HttpStatusCode.Conflict;
                                    sdTrResult.HttpMessage  = "";
                                    sdTrResult.HttpMethod   = "DELETE";
                                    sdTrResult.ResourceKind = resource;
                                    sdTrResult.Uuid         = entry.Uuid;
                                }

                                syncDigestStore.PersistNewer(resourceKind, resSyncInfo);
                            }
                            catch (Exception e)
                            {
                                sdTrResult              = new SdataTransactionResult();
                                sdTrResult.HttpStatus   = HttpStatusCode.Conflict;
                                sdTrResult.HttpMethod   = "PUT";
                                sdTrResult.HttpMessage  = e.ToString();
                                sdTrResult.ResourceKind = resource;
                                sdTrResult.Uuid         = entry.Uuid;
                            }
                            #endregion
                        }
                    }
                    catch (Exception e)
                    {
                        sdTrResult              = new SdataTransactionResult();
                        sdTrResult.HttpStatus   = HttpStatusCode.Conflict;
                        sdTrResult.HttpMessage  = e.ToString();
                        sdTrResult.ResourceKind = resource;
                        sdTrResult.Uuid         = entry.Uuid;
                    }

                    #region store transaction result

                    if (sdTrResult != null)
                    {
                        lock (_parentPerformer._asyncStateObj)
                        {
                            this._parentPerformer._asyncStateObj.TransactionResults.Add(sdTrResult);
                        }
                    }

                    #endregion
                }
                #endregion


                // Set tracking phase
                lock (_parentPerformer._asyncStateObj.Tracking)
                {
                    _parentPerformer._asyncStateObj.Tracking.Phase = TrackingPhase.FINISH;
                }
            }
示例#14
0
        public void DoWork(IRequest request)
        {
            EntryRequestType            entryRequestType;
            string                      resourceKindName;
            ICorrelatedResSyncInfoStore correlatedResSyncStore;
            bool includeDataPayloads;   //?includePayloads value

            CorrelatedResSyncInfo[] correlatedResSyncInfos;
            int totalResult;

            #region initialization

            // multi or single entry request?
            entryRequestType = (String.IsNullOrEmpty(_requestContext.ResourceKey)) ? EntryRequestType.Multi : EntryRequestType.Single;

            resourceKindName = _requestContext.ResourceKind.ToString();

            string tmpValue;
            // ?includePayloads
            includeDataPayloads = false;    // default value, but check for settings now
            if (_requestContext.SdataUri.QueryArgs.TryGetValue("includePayload", out tmpValue))
            {
                includeDataPayloads = System.Xml.XmlConvert.ToBoolean(tmpValue);
            }

            // get store to request the correlations
            correlatedResSyncStore = RequestReceiver.NorthwindAdapter.StoreLocator.GetCorrelatedResSyncStore(_requestContext.SdataContext);

            #endregion

            // receive correlated resource synchronization entries
            if (entryRequestType == EntryRequestType.Multi)
            {
                int pageNumber = FeedMetadataHelpers.GetPageNumber(_requestContext);

                correlatedResSyncInfos = correlatedResSyncStore.GetPaged(resourceKindName, pageNumber, FeedMetadataHelpers.DEFAULT_ITEMS_PER_PAGE, out totalResult);
            }
            else
            {
                Guid uuid = (Guid)TypeDescriptor.GetConverter(typeof(Guid)).ConvertFrom(_requestContext.ResourceKey);
                correlatedResSyncInfos = correlatedResSyncStore.GetByUuid(resourceKindName, new Guid[] { uuid });
                totalResult            = correlatedResSyncInfos.Length;
            }

            // Create the feed
            SyncFeed feed = new SyncFeed();

            // initialize the feed
            feed.Id    = FeedMetadataHelpers.BuildBaseUrl(_requestContext, FeedMetadataHelpers.RequestKeywordType.linked);
            feed.Title = string.Format("{0} Linking Feed", resourceKindName);

            #region PAGING & OPENSEARCH

            /* PAGING */
            feed.Links = FeedMetadataHelpers.CreatePageFeedLinks(_requestContext, totalResult, FeedMetadataHelpers.RequestKeywordType.linked);

            /* OPENSEARCH */
            PageController pageLinkBuilder = FeedMetadataHelpers.GetPageLinkBuilder(_requestContext, totalResult, FeedMetadataHelpers.RequestKeywordType.linked);

            feed.Opensearch_ItemsPerPageElement = pageLinkBuilder.GetOpensearch_ItemsPerPageElement();
            feed.Opensearch_StartIndexElement   = pageLinkBuilder.GetOpensearch_StartIndexElement();
            feed.Opensearch_TotalResultsElement = pageLinkBuilder.GetOpensearch_TotalResultsElement();

            #endregion

            feed.FeedType = (entryRequestType == EntryRequestType.Multi) ? FeedType.Linked : FeedType.LinkedSingle;

            IEntityWrapper wrapper = null;
            if (includeDataPayloads)
            {
                wrapper = EntityWrapperFactory.Create(_requestContext.ResourceKind, _requestContext);
            }

            for (int i = 0; i < correlatedResSyncInfos.Length; i++)
            {
                SyncFeedEntry entry = null;

                if (includeDataPayloads)
                {
                    entry = wrapper.GetFeedEntry(correlatedResSyncInfos[i].LocalId);
                }
                else
                {
                    entry = new SyncFeedEntry();
                }

                entry.Id    = FeedMetadataHelpers.BuildLinkedEntryUrl(_requestContext, correlatedResSyncInfos[i].ResSyncInfo.Uuid);
                entry.Title = FeedMetadataHelpers.BuildLinkedEntryTitle(_requestContext, correlatedResSyncInfos[i].ResSyncInfo.Uuid);

                #region LINKED ELEMENT

                LinkedElement linkedElement = new LinkedElement();
                linkedElement.Resource = FeedMetadataHelpers.BuildEntryResourceUrl(_requestContext, correlatedResSyncInfos[i].LocalId);
                linkedElement.Uuid     = correlatedResSyncInfos[i].ResSyncInfo.Uuid;
                entry.Linked           = linkedElement;

                #endregion

                feed.Entries.Add(entry);
            }

            request.Response.Serializer  = new SyncFeedSerializer();
            request.Response.Feed        = (IFeed)feed;
            request.Response.ContentType = (entryRequestType == EntryRequestType.Multi) ? MediaType.Atom : MediaType.AtomEntry;
        }
示例#15
0
        public void DoWork(IRequest request)
        {
            if (request.ContentType != Sage.Common.Syndication.MediaType.AtomEntry)
            {
                throw new RequestException("Atom entry content type expected");
            }

            if (String.IsNullOrEmpty(_requestContext.ResourceKey))
            {
                throw new RequestException("Please use single resource url");
            }
            //SupportedResourceKinds resKind = _requestContext.ResourceKind;
            //switch (resKind)
            //{
            //    case SupportedResourceKinds.tradingAccounts:
            //    case SupportedResourceKinds.contacts:
            //    case SupportedResourceKinds.phoneNumbers:
            //    case SupportedResourceKinds.postalAddresses:
            //        break;
            //    default:
            //        throw new RequestException("Put is not Supported for requested resource");
            //}

            // read entry from stream
            SyncFeedEntry entry  = new SyncFeedEntry();
            XmlReader     reader = XmlReader.Create(request.Stream);

            reader.MoveToContent();

            entry.ReadXml(reader, ResourceKindHelpers.GetPayloadType(_requestContext.ResourceKind));

            IEntityWrapper wrapper = EntityWrapperFactory.Create(_requestContext.ResourceKind, _requestContext);

            Token    emptyToken = new Token();
            Identity identity   = wrapper.GetIdentity(_requestContext.ResourceKey);

            Document originalDocument = wrapper.Entity.GetDocument(identity, emptyToken, _requestContext.Config);

            if (originalDocument.LogState == LogState.Deleted)
            {
                throw new RequestException("Entity does not exists");
            }

            entry.Payload.LocalID = _requestContext.ResourceKey;
            SdataTransactionResult sdTrResult = wrapper.Update(entry.Payload, entry.SyncLinks);

            if (sdTrResult == null)
            {
                SyncFeedEntry responseEntry = wrapper.GetFeedEntry(_requestContext.ResourceKey);

                SyncFeed feed = new SyncFeed();
                feed.FeedType = FeedType.ResourceEntry;
                feed.Entries.Add(responseEntry);
                request.Response.Serializer  = new SyncFeedSerializer();
                request.Response.Feed        = feed;
                request.Response.ContentType = Sage.Common.Syndication.MediaType.AtomEntry;
            }
            else if (sdTrResult.HttpStatus == System.Net.HttpStatusCode.OK)
            {
                SyncFeedEntry responseEntry = wrapper.GetFeedEntry(_requestContext.ResourceKey);

                SyncFeed feed = new SyncFeed();
                feed.FeedType = FeedType.ResourceEntry;
                feed.Entries.Add(responseEntry);
                request.Response.Serializer  = new SyncFeedSerializer();
                request.Response.Feed        = feed;
                request.Response.ContentType = Sage.Common.Syndication.MediaType.AtomEntry;
            }
            else
            {
                throw new RequestException(sdTrResult.HttpMessage);
            }
        }
            /// <summary>
            ///
            /// </summary>
            /// <param name="config"></param>
            /// <returns></returns>
            /// <remarks>This method is not threadsafe as the performer must be finished when calling this method.</remarks>
            public SyncFeed GetFeed(NorthwindConfig config, int startIndex, int count)
            {
                SyncFeed               feed;
                SdataContext           sdataContext;
                SupportedResourceKinds resource;
                string resourceKind;
                string endpoint;
                Guid   trackingId;

                List <SdataTransactionResult> transactinResults;

                sdataContext      = _parentPerformer._requestContext.SdataContext;
                resource          = _parentPerformer._requestContext.ResourceKind;
                resourceKind      = resource.ToString();
                transactinResults = _parentPerformer._asyncStateObj.TransactionResults;
                endpoint          = _parentPerformer._requestContext.DatasetLink + resourceKind;;
                trackingId        = _parentPerformer._requestContext.TrackingId;

                if (count == 0)
                {
                    count = 10;
                }

                feed = new SyncFeed();
                Token emptyToken = new Token();



                IEntityWrapper wrapper = EntityWrapperFactory.Create(resource, _parentPerformer._requestContext);



                for (int index = startIndex;
                     index < ((startIndex + count > transactinResults.Count) ? transactinResults.Count : startIndex + count);
                     index++)
                {
                    SdataTransactionResult transactionResult = (SdataTransactionResult)transactinResults[index];

                    SyncFeedEntry entry = wrapper.GetFeedEntry(transactionResult);

                    if (entry != null)
                    {
                        feed.Entries.Add(entry);
                    }
                    else
                    {
                        entry                = new SyncFeedEntry();
                        entry.Uuid           = transactionResult.Uuid;
                        entry.HttpStatusCode = transactionResult.HttpStatus;
                        entry.HttpMessage    = transactionResult.HttpMessage;;
                        entry.HttpMethod     = transactionResult.HttpMethod;
                        entry.HttpLocation   = transactionResult.Location;
                        entry.HttpETag       = transactionResult.Etag;
                        feed.Entries.Add(entry);
                    }
                }

                // initialize the feed
                string url = string.Format("{0}/$syncTarget('{1}')", endpoint, trackingId);

                feed.Title = resourceKind;
                feed.Id    = url;

                #region PAGING & OPENSEARCH

                int totalResults = transactinResults.Count;

                PageController pageController = new PageController(startIndex + 1, FeedMetadataHelpers.DEFAULT_ITEMS_PER_PAGE, totalResults, count, url);

                /* PAGING */
                FeedLinkCollection feedLinks = new FeedLinkCollection();
                feedLinks.Add(new FeedLink(pageController.GetLinkSelf(), LinkType.Self, MediaType.Atom, "Current Page"));
                feedLinks.Add(new FeedLink(pageController.GetLinkFirst(), LinkType.First, MediaType.Atom, "First Page"));
                feedLinks.Add(new FeedLink(pageController.GetLinkLast(), LinkType.Last, MediaType.Atom, "Last Page"));

                string linkUrl;
                if (pageController.GetLinkNext(out linkUrl))
                {
                    feedLinks.Add(new FeedLink(linkUrl, LinkType.Next, MediaType.Atom, "Next Page"));
                }
                if (pageController.GetLinkPrevious(out linkUrl))
                {
                    feedLinks.Add(new FeedLink(linkUrl, LinkType.Previous, MediaType.Atom, "Previous Page"));
                }

                feed.Links = feedLinks;


                /* OPENSEARCH */
                feed.Opensearch_ItemsPerPageElement = pageController.GetOpensearch_ItemsPerPageElement();
                feed.Opensearch_StartIndexElement   = pageController.GetOpensearch_StartIndexElement();
                feed.Opensearch_TotalResultsElement = pageController.GetOpensearch_TotalResultsElement();

                #endregion

                //if (startIndex + count < transactinResults.Count)
                //{
                //    FeedLink linkNext = new FeedLink(string.Format("{0}?startIndex={1}&count=10", url, startIndex + count), LinkType.Next);
                //    feed.Links.Add(linkNext);
                //}

                //FeedLink linkFirst = new FeedLink(String.Format("{0}?startIndex=0&count=10", url), LinkType.First);
                //feed.Links.Add(linkFirst);

                //FeedLink linkSelf = new FeedLink(String.Format("{0}?startIndex={1}&count=10", url, startIndex), LinkType.Self);
                //feed.Links.Add(linkSelf);

                return(feed);
            }
示例#17
0
 /// <summary>
 ///
 /// </summary>
 public void Add(TEntity entity)
 {
     EntityUtil.CheckArgumentNull(entity, "entity");
     Add(EntityWrapperFactory.WrapEntityUsingContext(entity, ObjectContext));
 }
            // Asynchronous called method
            private void Execute(NorthwindConfig config, SyncFeedDigest syncDigestInfo)
            {
                #region Declaration

                SdataContext                sdataContext;
                SupportedResourceKinds      resource;
                IAppBookmarkInfoStore       appBookmarkInfoStore;
                ICorrelatedResSyncInfoStore correlatedResSyncInfoStore;
                ISyncSyncDigestInfoStore    syncDigestStore;
                ISyncTickProvider           tickProvider;
                string         resourceKind;
                string         endpoint;
                int            nextTick = 0;
                Token          lastToken;
                Token          nextToken;
                Identity[]     changedIdentites;
                IEntityWrapper wrapper;

                #endregion

                #region init

                sdataContext               = _parentPerformer._requestContext.SdataContext;
                resource                   = _parentPerformer._requestContext.ResourceKind;
                resourceKind               = resource.ToString();
                endpoint                   = _parentPerformer._requestContext.DatasetLink + resourceKind;
                appBookmarkInfoStore       = RequestReceiver.NorthwindAdapter.StoreLocator.GetAppBookmarkStore(sdataContext);
                correlatedResSyncInfoStore = RequestReceiver.NorthwindAdapter.StoreLocator.GetCorrelatedResSyncStore(sdataContext);
                syncDigestStore            = RequestReceiver.NorthwindAdapter.StoreLocator.GetSyncDigestStore(sdataContext);
                tickProvider               = RequestReceiver.NorthwindAdapter.StoreLocator.GetTickProvider(sdataContext);

                wrapper = EntityWrapperFactory.Create(resource, _parentPerformer._requestContext);

                #endregion

                #region get last token or create a new one

                if (!appBookmarkInfoStore.Get <Token>(resourceKind, out lastToken))
                {
                    lastToken             = new Token();
                    lastToken.InitRequest = true;
                }

                #endregion


                #region Get local identities of changed entries since last synchronisation

                changedIdentites = wrapper.Entity.GetLastChanges(lastToken, config, out nextToken);

                #endregion

                if (resource == SupportedResourceKinds.phoneNumbers)
                {
                    #region workaround for phones
                    for (int index = 0; index < changedIdentites.Length; index++)
                    {
                        string phoneid = changedIdentites[index].Id + Sage.Integration.Northwind.Application.API.Constants.PhoneIdPostfix;
                        string faxId   = changedIdentites[index].Id + Sage.Integration.Northwind.Application.API.Constants.FaxIdPostfix;


                        // receive the feed entry for local identity
                        SyncFeedEntry phoneentry = wrapper.GetFeedEntry(phoneid);
                        SyncFeedEntry faxentry   = wrapper.GetFeedEntry(faxId);
                        if (phoneentry == null && faxentry == null)
                        {
                            continue;
                        }
                        // receive the correlation for the local identity


                        if (phoneentry != null)
                        {
                            CorrelatedResSyncInfo[] correlatedResSyncInfos = correlatedResSyncInfoStore.GetByLocalId(resourceKind, new string[] { phoneid });



                            string etag = EtagServices.ComputeEtag(phoneentry.Payload, true);   // new etag
                            if (correlatedResSyncInfos.Length == 0)
                            {
                                nextTick = tickProvider.CreateNextTick(resourceKind); // create next tick

                                ResSyncInfo           resyncInfo = new ResSyncInfo(Guid.NewGuid(), endpoint, nextTick, etag, DateTime.Now);
                                CorrelatedResSyncInfo info       = new CorrelatedResSyncInfo(phoneid, resyncInfo);

                                correlatedResSyncInfoStore.Put(resourceKind, info);

                                syncDigestStore.PersistNewer(resourceKind, info.ResSyncInfo);
                            }
                            else if (!correlatedResSyncInfos[0].ResSyncInfo.Etag.Equals(etag))
                            {
                                nextTick = tickProvider.CreateNextTick(resourceKind);
                                correlatedResSyncInfos[0].ResSyncInfo.Etag          = etag;
                                correlatedResSyncInfos[0].ResSyncInfo.Tick          = nextTick;
                                correlatedResSyncInfos[0].ResSyncInfo.Endpoint      = endpoint;
                                correlatedResSyncInfos[0].ResSyncInfo.ModifiedStamp = DateTime.Now;
                                correlatedResSyncInfoStore.Put(resourceKind, correlatedResSyncInfos[0]);

                                syncDigestStore.PersistNewer(resourceKind, correlatedResSyncInfos[0].ResSyncInfo);
                            }
                        }
                        if (faxentry != null)
                        {
                            CorrelatedResSyncInfo[] correlatedResSyncInfos = correlatedResSyncInfoStore.GetByLocalId(resourceKind, new string[] { faxId });

                            string etag = EtagServices.ComputeEtag(faxentry.Payload, true);   // new etag
                            if (correlatedResSyncInfos.Length == 0)
                            {
                                nextTick = tickProvider.CreateNextTick(resourceKind); // create next tick

                                ResSyncInfo           resyncInfo = new ResSyncInfo(Guid.NewGuid(), endpoint, nextTick, etag, DateTime.Now);
                                CorrelatedResSyncInfo info       = new CorrelatedResSyncInfo(faxId, resyncInfo);

                                correlatedResSyncInfoStore.Put(resourceKind, info);

                                syncDigestStore.PersistNewer(resourceKind, info.ResSyncInfo);
                            }
                            else if (!correlatedResSyncInfos[0].ResSyncInfo.Etag.Equals(etag))
                            {
                                nextTick = tickProvider.CreateNextTick(resourceKind);
                                correlatedResSyncInfos[0].ResSyncInfo.Etag          = etag;
                                correlatedResSyncInfos[0].ResSyncInfo.Tick          = nextTick;
                                correlatedResSyncInfos[0].ResSyncInfo.Endpoint      = endpoint;
                                correlatedResSyncInfos[0].ResSyncInfo.ModifiedStamp = DateTime.Now;
                                correlatedResSyncInfoStore.Put(resourceKind, correlatedResSyncInfos[0]);

                                syncDigestStore.PersistNewer(resourceKind, correlatedResSyncInfos[0].ResSyncInfo);
                            }
                        }
                    }
                    #endregion
                }
                else
                {
                    for (int index = 0; index < changedIdentites.Length; index++)
                    {
                        string id = changedIdentites[index].Id;
                        // receive the feed entry for local identity
                        SyncFeedEntry entry = wrapper.GetFeedEntry(id);
                        if (entry == null)
                        {
                            continue;
                        }
                        // receive the correlation for the local identity



                        CorrelatedResSyncInfo[] correlatedResSyncInfos = correlatedResSyncInfoStore.GetByLocalId(resourceKind, new string[] { id });



                        string etag = EtagServices.ComputeEtag(entry.Payload, true);   // new etag
                        if (correlatedResSyncInfos.Length == 0)
                        {
                            nextTick = tickProvider.CreateNextTick(resourceKind); // create next tick

                            ResSyncInfo           resyncInfo = new ResSyncInfo(Guid.NewGuid(), endpoint, nextTick, etag, DateTime.Now);
                            CorrelatedResSyncInfo info       = new CorrelatedResSyncInfo(id, resyncInfo);

                            correlatedResSyncInfoStore.Put(resourceKind, info);

                            syncDigestStore.PersistNewer(resourceKind, info.ResSyncInfo);
                        }
                        else if (!correlatedResSyncInfos[0].ResSyncInfo.Etag.Equals(etag))
                        {
                            nextTick = tickProvider.CreateNextTick(resourceKind);
                            correlatedResSyncInfos[0].ResSyncInfo.Etag          = etag;
                            correlatedResSyncInfos[0].ResSyncInfo.Tick          = nextTick;
                            correlatedResSyncInfos[0].ResSyncInfo.Endpoint      = endpoint;
                            correlatedResSyncInfos[0].ResSyncInfo.ModifiedStamp = DateTime.Now;
                            correlatedResSyncInfoStore.Put(resourceKind, correlatedResSyncInfos[0]);

                            syncDigestStore.PersistNewer(resourceKind, correlatedResSyncInfos[0].ResSyncInfo);
                        }
                    }
                }

                #region store next token

                appBookmarkInfoStore.Put(resourceKind, nextToken);

                #endregion

                // set tracking phase
                lock (_parentPerformer._asyncStateObj)
                {
                    _parentPerformer._asyncStateObj.Tracking.Phase = TrackingPhase.GETCHANGESBYTICK;
                }


                // Receive syncDigestInfo
                if (null != syncDigestInfo)
                {
                    ICorrelatedResSyncInfoEnumerator enumerator;
                    List <string> endpoints = new List <string>();

                    foreach (SyncFeedDigestEntry digestEntry in syncDigestInfo.Entries)
                    {
                        endpoints.Add(digestEntry.Endpoint);
                        enumerator = correlatedResSyncInfoStore.GetSinceTick(resourceKind, digestEntry.Endpoint, digestEntry.Tick - 2);
                        while (enumerator.MoveNext())
                        {
                            // No lock needed, as we expect that CorrelatedResSyncInfos list is
                            // only acceeded anywhere else when Tracking phase is 'finish'.
                            //lock(_parentPerformer._asyncStateObj)
                            //{
                            _parentPerformer._asyncStateObj.CorrelatedResSyncInfos.Add(enumerator.Current);
                            //}
                        }
                    }

                    SyncDigestInfo sourceSyncDigestInfo = syncDigestStore.Get(resourceKind);
                    foreach (SyncDigestEntryInfo digestEntry in sourceSyncDigestInfo)
                    {
                        if (endpoints.Contains(digestEntry.Endpoint))
                        {
                            continue;
                        }
                        endpoints.Add(digestEntry.Endpoint);
                        enumerator = correlatedResSyncInfoStore.GetSinceTick(resourceKind, digestEntry.Endpoint, -1);
                        while (enumerator.MoveNext())
                        {
                            // No lock needed, as we expect that CorrelatedResSyncInfos list is
                            // only acceeded anywhere else when Tracking phase is 'finish'.
                            //lock(_parentPerformer._asyncStateObj)
                            //{
                            _parentPerformer._asyncStateObj.CorrelatedResSyncInfos.Add(enumerator.Current);
                            //}
                        }
                    }
                    if (!endpoints.Contains(endpoint))
                    {
                        enumerator = correlatedResSyncInfoStore.GetSinceTick(resourceKind, endpoint, -1);
                        while (enumerator.MoveNext())
                        {
                            // No lock needed, as we expect that CorrelatedResSyncInfos list is
                            // only acceeded anywhere else when Tracking phase is 'finish'.
                            //lock(_parentPerformer._asyncStateObj)
                            //{
                            _parentPerformer._asyncStateObj.CorrelatedResSyncInfos.Add(enumerator.Current);
                            //}
                        }
                    }
                }



                // Set tracking phase
                lock (_parentPerformer._asyncStateObj.Tracking)
                {
                    _parentPerformer._asyncStateObj.Tracking.Phase = TrackingPhase.FINISH;
                }
            }
            /// <summary>
            ///
            /// </summary>
            /// <param name="config"></param>
            /// <returns></returns>
            /// <remarks>This method is not threadsafe as the performer must be finished when calling this method.</remarks>
            public SyncFeed GetFeed(NorthwindConfig config, int startIndex, int count)
            {
                SyncFeed               feed;
                SdataContext           sdataContext;
                SupportedResourceKinds resource;
                string resourceKind;
                string endpoint;
                Guid   trackingId;


                List <CorrelatedResSyncInfo> correlatedResSyncInfos;

                sdataContext           = _parentPerformer._requestContext.SdataContext;
                resource               = _parentPerformer._requestContext.ResourceKind;
                resourceKind           = resource.ToString();
                correlatedResSyncInfos = _parentPerformer._asyncStateObj.CorrelatedResSyncInfos;
                endpoint               = _parentPerformer._requestContext.DatasetLink + resourceKind;
                trackingId             = _parentPerformer._requestContext.TrackingId;


                ISyncSyncDigestInfoStore syncDigestStore = RequestReceiver.NorthwindAdapter.StoreLocator.GetSyncDigestStore(sdataContext);
                SyncDigestInfo           syncDigestInfo  = syncDigestStore.Get(resourceKind);


                if (count == 0)
                {
                    count = 10;
                }

                feed = new SyncFeed();
                Token emptyToken = new Token();

                feed.Digest         = new SyncFeedDigest();
                feed.Digest.Origin  = _parentPerformer._requestContext.OriginEndPoint;
                feed.Digest.Entries = new List <SyncFeedDigestEntry>();

                if (syncDigestInfo != null)
                {
                    foreach (SyncDigestEntryInfo entryinfo in syncDigestInfo)
                    {
                        SyncFeedDigestEntry entry = new SyncFeedDigestEntry();
                        entry.ConflictPriority = entryinfo.ConflictPriority;
                        entry.Endpoint         = entryinfo.Endpoint;
                        entry.Tick             = entryinfo.Tick;
                        entry.Stamp            = DateTime.Now;
                        feed.Digest.Entries.Add(entry);
                    }
                }



                IEntityWrapper wrapper = EntityWrapperFactory.Create(resource, _parentPerformer._requestContext);


                for (int index = startIndex;
                     index < ((startIndex + count > correlatedResSyncInfos.Count) ? correlatedResSyncInfos.Count : startIndex + count);
                     index++)
                {
                    CorrelatedResSyncInfo resSyncInfo = (CorrelatedResSyncInfo)correlatedResSyncInfos[index];
                    SyncFeedEntry         entry       = wrapper.GetFeedEntry(resSyncInfo);
                    if (entry != null)
                    {
                        feed.Entries.Add(entry);
                    }
                    else
                    {
                        entry            = new SyncFeedEntry();
                        entry.HttpMethod = "DELETE";
                        entry.Uuid       = resSyncInfo.ResSyncInfo.Uuid;
                        feed.Entries.Add(entry);
                    }
                }


                // initialize the feed
                string url = string.Format("{0}/$syncSource('{1}')", endpoint, trackingId);

                feed.Id    = url;
                feed.Title = resourceKind;

                #region PAGING & OPENSEARCH

                int totalResults = correlatedResSyncInfos.Count;

                PageController pageController = new PageController(startIndex + 1, FeedMetadataHelpers.DEFAULT_ITEMS_PER_PAGE, totalResults, count, url);

                /* PAGING */
                FeedLinkCollection feedLinks = new FeedLinkCollection();
                feedLinks.Add(new FeedLink(pageController.GetLinkSelf(), LinkType.Self, MediaType.Atom, "Current Page"));
                feedLinks.Add(new FeedLink(pageController.GetLinkFirst(), LinkType.First, MediaType.Atom, "First Page"));
                feedLinks.Add(new FeedLink(pageController.GetLinkLast(), LinkType.Last, MediaType.Atom, "Last Page"));

                string linkUrl;
                if (pageController.GetLinkNext(out linkUrl))
                {
                    feedLinks.Add(new FeedLink(linkUrl, LinkType.Next, MediaType.Atom, "Next Page"));
                }
                if (pageController.GetLinkPrevious(out linkUrl))
                {
                    feedLinks.Add(new FeedLink(linkUrl, LinkType.Previous, MediaType.Atom, "Previous Page"));
                }

                feed.Links = feedLinks;


                /* OPENSEARCH */
                feed.Opensearch_ItemsPerPageElement = pageController.GetOpensearch_ItemsPerPageElement();
                feed.Opensearch_StartIndexElement   = pageController.GetOpensearch_StartIndexElement();
                feed.Opensearch_TotalResultsElement = pageController.GetOpensearch_TotalResultsElement();

                #endregion



                //feed.Id = url;
                //if (startIndex + count < correlatedResSyncInfos.Count)
                //{
                //    FeedLink linkNext = new FeedLink(string.Format("{0}?startIndex={1}&count=10", url, startIndex + count), LinkType.Next);
                //    feed.Links.Add(linkNext);
                //}

                //FeedLink linkFirst = new FeedLink(String.Format("{0}?startIndex=0&count=10", url), LinkType.First);
                //feed.Links.Add(linkFirst);

                //FeedLink linkSelf = new FeedLink(String.Format("{0}?startIndex={1}&count=10", url, startIndex), LinkType.Self);
                //feed.Links.Add(linkSelf);

                return(feed);
            }