public Link CreateDocumentLink(IHypermediaContext hypermediaContext, IDocumentPathContext documentPathContext, DocumentType documentType, Type clrResourceType, object clrResource, ILinkContext linkContext)
        {
            Contract.Requires(hypermediaContext != null);
            Contract.Requires(documentPathContext != null);
            Contract.Requires(clrResourceType != null);
            Contract.Requires(clrResource != null);
            Contract.Requires(linkContext != null);

            var apiDocumentLink = CreateStandardDocumentLink(hypermediaContext, documentPathContext, linkContext);

            if (apiDocumentLink != null)
            {
                return(apiDocumentLink);
            }

            var urlBuilderConfiguration        = hypermediaContext.GetUrlBuilderConfiguration(clrResourceType);
            var throwExceptionOnLinkBuildError = urlBuilderConfiguration.ThrowExceptionOnLinkBuildError;

            if (throwExceptionOnLinkBuildError == false)
            {
                return(null);
            }

            var apiRel = linkContext.Rel;
            var detail = ServerErrorStrings.DocumentBuildExceptionDetailBuildNonStandardDocumentLink
                         .FormatWith(apiRel);

            throw new DocumentBuildException(detail);
        }
Пример #2
0
 public DocumentPathContextCreateWithUrlAndHypermediaContextTest(IHypermediaContext hypermediaContext, string urlString, IEnumerable <Type> expectedClrResourceTypes, IEnumerable <IHypermediaPath> expectedDocumentSelfPath)
 {
     this.HypermediaContext        = hypermediaContext;
     this.UrlString                = urlString;
     this.ExpectedClrResourceTypes = expectedClrResourceTypes;
     this.ExpectedDocumentSelfPath = expectedDocumentSelfPath;
 }
Пример #3
0
        private static Link CreateResourceRelationshipLink(IHypermediaContext hypermediaContext,
                                                           IResourcePathContext resourcePathContext,
                                                           IResourceType resourceType,
                                                           object clrResource,
                                                           bool addRelationshipsPathSegment,
                                                           IRelationshipInfo relationship,
                                                           Meta apiRelationshipLinkMeta)
        {
            Contract.Requires(hypermediaContext != null);
            Contract.Requires(resourcePathContext != null);
            Contract.Requires(resourceType != null);
            Contract.Requires(clrResource != null);
            Contract.Requires(relationship != null);

            var clrResourceType         = resourceType.ClrType;
            var urlBuilderConfiguration = hypermediaContext.GetUrlBuilderConfiguration(clrResourceType);

            var apiId           = resourceType.GetApiId(clrResource);
            var apiResourcePath = resourcePathContext.GetResourceSelfPath(apiId);
            var apiRelationshipRelPathSegment = relationship.ApiRelPathSegment;
            var apiRelationshipLinkHRef       = UrlBuilder.Create(urlBuilderConfiguration)
                                                .Path(apiResourcePath)
                                                .Path(Keywords.Relationships, addRelationshipsPathSegment)
                                                .Path(apiRelationshipRelPathSegment)
                                                .Build();
            var apiRelationshipLink = new Link
            {
                HRef = apiRelationshipLinkHRef,
                Meta = apiRelationshipLinkMeta
            };

            return(apiRelationshipLink);
        }
        private static Links CreateResourceRelationshipLinks(IHypermediaContext hypermediaContext, IResourcePathContext resourcePathContext, IResourceType resourceType, object clrResource, IRelationshipInfo relationship, IRelationshipContext relationshipContext)
        {
            Contract.Requires(hypermediaContext != null);
            Contract.Requires(resourcePathContext != null);
            Contract.Requires(resourceType != null);
            Contract.Requires(clrResource != null);
            Contract.Requires(relationship != null);
            Contract.Requires(relationshipContext != null);

            var apiRelationshipHasLinks = relationshipContext.HasLinks();

            if (!apiRelationshipHasLinks)
            {
                return(null);
            }

            var links = relationshipContext.LinkContexts;
            var apiRelationshipRelToLinkDictionary = links
                                                     .Select(x =>
            {
                var rel        = x.Rel;
                var meta       = x.Meta;
                var isSelfLink = String.Compare(Keywords.Self, rel, StringComparison.Ordinal) == 0;
                var link       = CreateResourceRelationshipLink(hypermediaContext, resourcePathContext, resourceType, clrResource, isSelfLink, relationship, meta);
                return(new Tuple <string, Link>(rel, link));
            })
                                                     .ToDictionary(x => x.Item1, x => x.Item2);

            var apiRelationshipLinks = new Links(apiRelationshipRelToLinkDictionary);

            return(apiRelationshipLinks);
        }
        // PRIVATE METHODS //////////////////////////////////////////////////
        #region Methods
        private static Link CreateStandardDocumentLink(IHypermediaContext hypermediaContext, IDocumentPathContext documentPathContext, ILinkContext linkContext)
        {
            Contract.Requires(hypermediaContext != null);
            Contract.Requires(documentPathContext != null);
            Contract.Requires(linkContext != null);

            var apiRel      = linkContext.Rel;
            var apiLinkMeta = linkContext.Meta;

            switch (apiRel)
            {
            case Keywords.Up:
            case Keywords.Self:
            {
                var urlBuilderConfiguration = hypermediaContext.UrlBuilderConfiguration;
                var apiDocumentSelfPath     = documentPathContext.DocumentSelfPath;

                var apiHRef = UrlBuilder.Create(urlBuilderConfiguration)
                              .Path(apiDocumentSelfPath)
                              .RemoveLastPathSegment(apiRel == Keywords.Up)
                              .Build();
                var apiDocumentLink = new Link
                {
                    HRef = apiHRef,
                    Meta = apiLinkMeta
                };
                return(apiDocumentLink);
            }
            }

            return(null);
        }
        private static void ResolveResourceLink(IDomLink domLink,
                                                IHypermediaContext hypermediaContext,
                                                IHypermediaAssembler hypermediaAssembler,
                                                IResourcePathContext resourcePathContext,
                                                Type clrResourceType,
                                                object clrResource,
                                                DomReadWriteLinks domReadWriteLinks)
        {
            if (domLink.IsReadOnly)
            {
                return;
            }

            // Resolve read-write resource link
            var domReadWriteLink = (DomReadWriteLink)domLink;
            var apiLinkRel       = domReadWriteLink.Rel;

            var apiLinkMeta = default(Meta);
            var domLinkMeta = (IDomMeta)domReadWriteLink.GetNode(DomNodeType.Meta);

            if (domLinkMeta != null)
            {
                apiLinkMeta = domLinkMeta.Meta;
            }

            // Create link.
            var linkContext     = new LinkContext(apiLinkRel, apiLinkMeta);
            var apiResourceLink = hypermediaAssembler.CreateResourceLink(hypermediaContext, resourcePathContext, clrResourceType, clrResource, linkContext);

            // Replace the old DOM read-write link node with a new DOM read-only link created by the framework.
            var domReadOnlyLink = DomReadOnlyLink.Create(apiLinkRel, apiResourceLink);

            domReadWriteLinks.ReplaceNode(domReadWriteLink, domReadOnlyLink);
        }
        // PUBLIC METHODS ///////////////////////////////////////////////////
        #region Extensions Methods
        public static UrlBuilder CreateUrlBuilder(this IHypermediaContext hypermediaContext)
        {
            Contract.Requires(hypermediaContext != null);

            var urlBuilderConfiguration = hypermediaContext.UrlBuilderConfiguration;
            var urlBuilder = UrlBuilder.Create(urlBuilderConfiguration);

            return(urlBuilder);
        }
        public static UrlBuilder CreateUrlBuilder <TResource>(this IHypermediaContext hypermediaContext)
            where TResource : class
        {
            Contract.Requires(hypermediaContext != null);

            var resourceType = typeof(TResource);

            return(hypermediaContext.CreateUrlBuilder(resourceType));
        }
        // PUBLIC METHODS ///////////////////////////////////////////////////
        #region Extensions Methods
        public static UrlBuilder CreateUrlBuilder(this IHypermediaContext hypermediaContext, Type resourceType)
        {
            Contract.Requires(hypermediaContext != null);
            Contract.Requires(resourceType != null);

            var urlBuilderConfiguration = hypermediaContext.GetUrlBuilderConfiguration(resourceType);
            var urlBuilder = UrlBuilder.Create(urlBuilderConfiguration);

            return(urlBuilder);
        }
Пример #10
0
        public DocumentPathContext(IHypermediaContext hypermediaContext, Uri url)
        {
            Contract.Requires(url != null);
            Contract.Requires(hypermediaContext != null);

            var documentSelfPath = url.ParseDocumentSelfPath(hypermediaContext);

            this.DocumentSelfPath = documentSelfPath;

            this.DocumentSelfQuery = url.Query;
        }
        public DocumentPathContext(IHypermediaContext hypermediaContext, Uri url)
        {
            Contract.Requires(url != null);
            Contract.Requires(hypermediaContext != null);

            var serviceModel            = hypermediaContext.ServiceModel;
            var urlBuilderConfiguration = hypermediaContext.UrlBuilderConfiguration;

            var documentSelfPath = url.ParseDocumentSelfPath(serviceModel, urlBuilderConfiguration);

            this.DocumentSelfPath = documentSelfPath;
        }
        private static IDocumentPathContext CreateDocumentPathContext(IHypermediaContext hypermediaContext, DocumentBuilderContext documentBuilderContext)
        {
            Contract.Requires(hypermediaContext != null);
            Contract.Requires(documentBuilderContext != null);

            var currentRequestUrl = documentBuilderContext.CurrentRequestUrl;

            if (currentRequestUrl == null)
            {
                return(null);
            }

            var documentPathContext = new DocumentPathContext(hypermediaContext, currentRequestUrl);

            return(documentPathContext);
        }
Пример #13
0
        // PUBLIC METHODS ///////////////////////////////////////////////////
        #region IHypermediaAssembler Implementation
        public Link CreateDocumentLink(IHypermediaContext hypermediaContext, IDocumentPathContext documentPathContext, DocumentType documentType, ILinkContext linkContext)
        {
            Contract.Requires(hypermediaContext != null);
            Contract.Requires(documentPathContext != null);
            Contract.Requires(linkContext != null);

            var apiDocumentLink = CreateStandardDocumentLink(hypermediaContext, documentPathContext, linkContext);

            if (apiDocumentLink != null)
            {
                return(apiDocumentLink);
            }

            var apiRel = linkContext.Rel;
            var detail = ServerErrorStrings.DocumentBuildExceptionDetailBuildNonStandardDocumentLink
                         .FormatWith(apiRel);

            throw new DocumentBuildException(detail);
        }
        // INTERNAL CONSTRUCTORS ////////////////////////////////////////////
        #region Constructors
        internal DocumentBuilder(DocumentWriter documentWriter,
                                 IHypermediaAssemblerRegistry hypermediaAssemblerRegistry,
                                 IHypermediaContext hypermediaContext,
                                 DocumentBuilderContext documentBuilderContext)
        {
            Contract.Requires(documentWriter != null);
            Contract.Requires(documentBuilderContext != null);

            var serviceModel = documentWriter.ServiceModel;
            var domDocument  = documentWriter.DomDocument;

            this.DomDocument    = domDocument;
            this.ServiceModel   = serviceModel;
            this.DocumentWriter = documentWriter;
            this.HypermediaAssemblerRegistry = hypermediaAssemblerRegistry;
            this.HypermediaContext           = hypermediaContext;
            this.DocumentBuilderContext      = documentBuilderContext;

            this.SetDocumentPathContextNodeAttribute();
        }
Пример #15
0
        private static Link CreateStandardResourceLink(IHypermediaContext hypermediaContext, IResourcePathContext resourcePathContext, Type clrResourceType, object clrResource, ILinkContext linkContext)
        {
            Contract.Requires(hypermediaContext != null);
            Contract.Requires(resourcePathContext != null);
            Contract.Requires(clrResourceType != null);
            Contract.Requires(clrResource != null);
            Contract.Requires(linkContext != null);

            var apiRel      = linkContext.Rel;
            var apiLinkMeta = linkContext.Meta;

            switch (apiRel)
            {
            case Keywords.Canonical:
            case Keywords.Self:
            {
                var urlBuilderConfiguration = hypermediaContext.GetUrlBuilderConfiguration(clrResourceType);

                var serviceModel = hypermediaContext.GetServiceModel();
                var resourceType = serviceModel.GetResourceType(clrResourceType);

                var isSelfLink = String.Compare(Keywords.Self, apiRel, StringComparison.Ordinal) == 0;

                var apiId           = resourceType.GetApiId(clrResource);
                var apiResourcePath = isSelfLink
                        ? resourcePathContext.GetResourceSelfPath(apiId)
                        : resourcePathContext.GetResourceCanonicalPath(apiId);
                var apiHRef = UrlBuilder.Create(urlBuilderConfiguration)
                              .Path(apiResourcePath)
                              .Build();
                var apiResourceLink = new Link
                {
                    HRef = apiHRef,
                    Meta = apiLinkMeta
                };
                return(apiResourceLink);
            }
            }

            return(null);
        }
        private void ResolveResourceRelationships(DomReadWriteResource domReadWriteResource,
                                                  IHypermediaContext hypermediaContext,
                                                  IHypermediaAssembler hypermediaAssembler,
                                                  IResourcePathContext resourcePathContext,
                                                  Type clrResourceType,
                                                  object clrResource)
        {
            var domRelationships = (IDomRelationships)domReadWriteResource.GetNode(DomNodeType.Relationships);

            if (domRelationships == null || domRelationships.IsReadOnly)
            {
                return;
            }

            var domReadWriteRelationships = (DomReadWriteRelationships)domRelationships;

            foreach (var domRelationship in domReadWriteRelationships.Nodes().Cast <IDomRelationship>())
            {
                this.ResolveResourceRelationship(domRelationship, hypermediaContext, hypermediaAssembler, resourcePathContext, clrResourceType, clrResource, domReadWriteRelationships);
            }
        }
        private static void ResolveResourceLinks(DomReadWriteResource domReadWriteResource,
                                                 IHypermediaContext hypermediaContext,
                                                 IHypermediaAssembler hypermediaAssembler,
                                                 IResourcePathContext resourcePathContext,
                                                 Type clrResourceType,
                                                 object clrResource)
        {
            var domLinks = (IDomLinks)domReadWriteResource.GetNode(DomNodeType.Links);

            if (domLinks == null || domLinks.IsReadOnly)
            {
                return;
            }

            var domReadWriteLinks = (DomReadWriteLinks)domLinks;

            foreach (var domLink in domReadWriteLinks.Nodes().Cast <IDomLink>())
            {
                ResolveResourceLink(domLink, hypermediaContext, hypermediaAssembler, resourcePathContext, clrResourceType, clrResource, domReadWriteLinks);
            }
        }
Пример #18
0
        public Link CreateResourceLink(IHypermediaContext hypermediaContext, IResourcePathContext resourcePathContext, Type clrResourceType, object clrResource, ILinkContext linkContext)
        {
            Contract.Requires(hypermediaContext != null);
            Contract.Requires(resourcePathContext != null);
            Contract.Requires(clrResourceType != null);
            Contract.Requires(clrResource != null);
            Contract.Requires(linkContext != null);

            var apiResourceLink = CreateStandardResourceLink(hypermediaContext, resourcePathContext, clrResourceType, clrResource, linkContext);

            if (apiResourceLink != null)
            {
                return(apiResourceLink);
            }

            var apiRel = linkContext.Rel;
            var clrResourceTypeName = clrResourceType.Name;
            var detail = ServerErrorStrings.DocumentBuildExceptionDetailBuildNonStandardResourceLink
                         .FormatWith(apiRel, clrResourceTypeName);

            throw new DocumentBuildException(detail);
        }
Пример #19
0
        public Relationship CreateResourceRelationship(IHypermediaContext hypermediaContext, IResourcePathContext resourcePathContext, Type clrResourceType, object clrResource, IRelationshipContext relationshipContext)
        {
            Contract.Requires(hypermediaContext != null);
            Contract.Requires(resourcePathContext != null);
            Contract.Requires(clrResourceType != null);
            Contract.Requires(clrResource != null);
            Contract.Requires(relationshipContext != null);

            var apiRel = relationshipContext.Rel;

            var serviceModel = hypermediaContext.GetServiceModel();
            var resourceType = serviceModel.GetResourceType(clrResourceType);
            var relationship = resourceType.GetRelationshipInfo(apiRel);

            // Create the Links object of the relationship.
            var apiRelationshipLinks = CreateResourceRelationshipLinks(hypermediaContext, resourcePathContext, resourceType, clrResource, relationship, relationshipContext);

            // Create the relationship:
            var apiRelationship = CreateResourceRelationship(apiRelationshipLinks, resourceType, relationship, relationshipContext);

            return(apiRelationship);
        }
        public static void SetHypermediaContext(this IDocumentContextImplementation implementation, IHypermediaContext hypermediaContext)
        {
            Contract.Requires(implementation != null);
            Contract.Requires(hypermediaContext != null);

            implementation.Options.ModifyExtension <ServerDocumentContextExtension>(x => x.HypermediaContext = hypermediaContext);
        }
Пример #21
0
        // PRIVATE METHODS //////////////////////////////////////////////////
        #region Methods
        private static Link CreateStandardDocumentLink(IHypermediaContext hypermediaContext, IDocumentPathContext documentPathContext, ILinkContext linkContext)
        {
            Contract.Requires(hypermediaContext != null);
            Contract.Requires(documentPathContext != null);
            Contract.Requires(linkContext != null);

            var apiRel      = linkContext.Rel;
            var apiLinkMeta = linkContext.Meta;

            switch (apiRel)
            {
            case Keywords.Up:
            {
                var apiDocumentSelfPath = documentPathContext.DocumentSelfPath
                                          .SafeToList();
                var apiDocumentSelfPathCount = apiDocumentSelfPath.Count;

                var apiDocumentUpPath = new List <IHypermediaPath>(apiDocumentSelfPathCount);
                for (var i = 0; i < apiDocumentSelfPathCount; ++i)
                {
                    var hypermediaPath = apiDocumentSelfPath[i];

                    var lastHypermediaPath = i == apiDocumentSelfPathCount - 1;
                    if (lastHypermediaPath)
                    {
                        var hypermediaPathType = hypermediaPath.HypermediaPathType;
                        switch (hypermediaPathType)
                        {
                        // Don't add the last hypermedia path.
                        case HypermediaPathType.ResourceCollectionPath:
                        case HypermediaPathType.ToOneResourcePath:
                        case HypermediaPathType.ToManyResourceCollectionPath:
                        case HypermediaPathType.NonResourcePath:
                        case HypermediaPathType.SingletonPath:
                            continue;

                        case HypermediaPathType.ResourcePath:
                        {
                            // Turn last resource path into a resource collection path.
                            var resourceHypermediaPath           = (ResourceHypermediaPath)hypermediaPath;
                            var clrResourceType                  = resourceHypermediaPath.ClrResourceType;
                            var apiCollectionPathSegment         = resourceHypermediaPath.ApiCollectionPathSegment;
                            var resourceCollectionHypermediaPath = new ResourceCollectionHypermediaPath(clrResourceType, apiCollectionPathSegment);

                            hypermediaPath = resourceCollectionHypermediaPath;
                        }
                        break;

                        case HypermediaPathType.ToManyResourcePath:
                        {
                            // Turn last resource path into a to-many resource collection path.
                            var toManyResourceHypermediaPath = (ToManyResourceHypermediaPath)hypermediaPath;
                            var clrResourceType                        = toManyResourceHypermediaPath.ClrResourceType;
                            var apiRelationshipPathSegment             = toManyResourceHypermediaPath.ApiRelationshipPathSegment;
                            var toManyResourceCollectionHypermediaPath = new ToManyResourceCollectionHypermediaPath(clrResourceType, apiRelationshipPathSegment);

                            hypermediaPath = toManyResourceCollectionHypermediaPath;
                        }
                        break;

                        default:
                            throw new ArgumentOutOfRangeException();
                        }
                    }

                    apiDocumentUpPath.Add(hypermediaPath);
                }

                if (apiDocumentUpPath.Any() == false)
                {
                    return(null);
                }

                var apiDocumentUpPathContext = new DocumentPathContext(apiDocumentUpPath);

                var clrPrimaryResourceType = apiDocumentUpPathContext.ClrResourceTypes.Any()
                        ? apiDocumentUpPathContext.GetPrimaryClrResourceType()
                        : documentPathContext.GetPrimaryClrResourceType();

                var urlBuilderConfiguration = hypermediaContext.GetUrlBuilderConfiguration(clrPrimaryResourceType);

                var apiHRef = UrlBuilder.Create(urlBuilderConfiguration)
                              .Path(apiDocumentUpPath)
                              .Build();
                var apiDocumentLink = new Link
                {
                    HRef = apiHRef,
                    Meta = apiLinkMeta
                };
                return(apiDocumentLink);
            }

            case Keywords.Self:
            {
                // Get the resource type that generated this document.
                var clrSelfResourceType             = documentPathContext.GetPrimaryClrResourceType();
                var apiDocumentSelfPath             = documentPathContext.DocumentSelfPath.SafeToReadOnlyCollection();
                var apiDocumentSelfPathClrTypesOnly = apiDocumentSelfPath.Where(x => x.HasClrResourceType())
                                                      .ToList();
                var apiDocumentSelfPathClrTypesOnlyCount = apiDocumentSelfPathClrTypesOnly.Count;
                if (apiDocumentSelfPathClrTypesOnlyCount > 1)
                {
                    var lastHypermediaPath     = apiDocumentSelfPathClrTypesOnly[apiDocumentSelfPathClrTypesOnlyCount - 1];
                    var lastHypermediaPathType = lastHypermediaPath.HypermediaPathType;
                    switch (lastHypermediaPathType)
                    {
                    case HypermediaPathType.ToOneResourcePath:
                    case HypermediaPathType.ToManyResourceCollectionPath:
                    {
                        var nextToLastHypermediaPath = apiDocumentSelfPathClrTypesOnly[apiDocumentSelfPathClrTypesOnlyCount - 2];
                        clrSelfResourceType = nextToLastHypermediaPath.GetClrResourceType();
                        break;
                    }
                    }
                }

                var urlBuilderConfiguration = hypermediaContext.GetUrlBuilderConfiguration(clrSelfResourceType);

                var query = documentPathContext.DocumentSelfQuery;

                var apiHRef = UrlBuilder.Create(urlBuilderConfiguration)
                              .Path(apiDocumentSelfPath)
                              .Query(query)
                              .Build();
                var apiDocumentLink = new Link
                {
                    HRef = apiHRef,
                    Meta = apiLinkMeta
                };
                return(apiDocumentLink);
            }
            }

            return(null);
        }
Пример #22
0
        // PUBLIC METHODS ///////////////////////////////////////////////////
        #region Extensions Methods
        public static IEnumerable <IHypermediaPath> ParseDocumentSelfPath(this Uri url, IHypermediaContext hypermediaContext)
        {
            Contract.Requires(url != null);
            Contract.Requires(hypermediaContext != null);

            // Create a URL path segment enumerator to enumerate over the URL path segments.
            var urlPathSegmentsFromUri = new List <string>(GetUrlPathSegments(url));

            // Remove any root path segments
            var uriBuilderConfiguration = hypermediaContext.GetUrlBuilderConfiguration(url);

            if (uriBuilderConfiguration.RootPathSegments != null)
            {
                var rootPathSegments      = uriBuilderConfiguration.RootPathSegments.SafeToReadOnlyList();
                var rootPathSegmentsCount = rootPathSegments.Count;

                urlPathSegmentsFromUri = urlPathSegmentsFromUri.SkipWhile((pathSegment, index) =>
                {
                    if (index >= rootPathSegmentsCount)
                    {
                        return(false);
                    }

                    var rootPathSegment = rootPathSegments[index];
                    var rootPathSegmentEqualToPathSegment = String.CompareOrdinal(rootPathSegment, pathSegment) == 0;
                    return(rootPathSegmentEqualToPathSegment);
                })
                                         .ToList();
            }

            var urlPathSegments = new List <string>();

            var serviceModel       = hypermediaContext.GetServiceModel();
            var homeDocumentExists = serviceModel.TryGetHomeResourceType(out var homeResourceType);

            if (homeDocumentExists)
            {
                var homeResourceTypeApiCollectionPathSegment = homeResourceType.HypermediaInfo.ApiCollectionPathSegment;
                if (String.IsNullOrEmpty(homeResourceTypeApiCollectionPathSegment))
                {
                    urlPathSegments.Add(String.Empty);
                }
            }

            urlPathSegments.AddRange(urlPathSegmentsFromUri);

            var urlPathSegmentsEnumerator = (IEnumerator <string>)urlPathSegments.GetEnumerator();

            // Parse the raw URL path for document self link path objects by
            // looking for the following:
            // 1. resource collection hypermedia path objects
            // 2. resource hypermedia path objects
            // 3. non-resource hypermedia path objects
            // 4. to-many resource collection hypermedia path objects
            // 5. to-many resource hypermedia path objects
            var documentSelfPath  = new List <IHypermediaPath>();
            var continueIterating = InitialIteration(serviceModel, urlPathSegmentsEnumerator, documentSelfPath);

            if (continueIterating && homeDocumentExists)
            {
                continueIterating = InitialIteration(serviceModel, urlPathSegmentsEnumerator, documentSelfPath);
            }

            while (continueIterating)
            {
                continueIterating = NextIteration(serviceModel, urlPathSegmentsEnumerator, documentSelfPath);
            }

            return(documentSelfPath);
        }
 public DocumentPathContext(IHypermediaContext hypermediaContext, string urlString)
     : this(hypermediaContext, new Uri(urlString))
 {
 }
        private void ResolveResourceRelationship(IDomRelationship domRelationship,
                                                 IHypermediaContext hypermediaContext,
                                                 IHypermediaAssembler hypermediaAssembler,
                                                 IResourcePathContext resourcePathContext,
                                                 Type clrResourceType,
                                                 object clrResource,
                                                 DomReadWriteRelationships domReadWriteRelationships)
        {
            if (domRelationship.IsReadOnly)
            {
                return;
            }

            // Resolve read-write relationship
            var domReadWriteRelationship = (DomReadWriteRelationship)domRelationship;

            // .. Rel
            var apiRelationshipRel = domReadWriteRelationship.Rel;

            // .. Links
            var linkContexts         = new List <ILinkContext>();
            var domRelationshipLinks = (IDomLinks)domReadWriteRelationship.GetNode(DomNodeType.Links);

            if (domRelationshipLinks != null)
            {
                if (domRelationshipLinks.IsReadOnly)
                {
                    // A read-write relationship contains unexpected read-only relationship links.
                    var detail = ServerErrorStrings.DomExceptionDetailReadWriteNodeHasUnexpectedReadOnlyChildNode
                                 .FormatWith(DomNodeType.Relationship, DomNodeType.Links);
                    throw new DomException(detail);
                }

                var domReadWriteRelationshipLinks = (DomReadWriteLinks)domRelationshipLinks;
                foreach (var domLink in domReadWriteRelationshipLinks.Nodes().Cast <IDomLink>())
                {
                    if (domLink.IsReadOnly)
                    {
                        // A read-write relationship contains unexpected read-only relationship link.
                        var detail = ServerErrorStrings.DomExceptionDetailReadWriteNodeHasUnexpectedReadOnlyChildNode
                                     .FormatWith(DomNodeType.Relationship, DomNodeType.Link);
                        throw new DomException(detail);
                    }

                    // Resolve read-write relationship link
                    var domReadWriteLink = (DomReadWriteLink)domLink;
                    var apiLinkRel       = domReadWriteLink.Rel;

                    var apiLinkMeta = default(Meta);
                    var domMeta     = (IDomMeta)domReadWriteLink.GetNode(DomNodeType.Meta);
                    if (domMeta != null)
                    {
                        apiLinkMeta = domMeta.Meta;
                    }

                    var linkContext = new LinkContext(apiLinkRel, apiLinkMeta);
                    linkContexts.Add(linkContext);
                }
            }

            // .. Data
            var resourceType = this.ServiceModel.GetResourceType(clrResourceType);
            var fromApiResourceIdentifier = resourceType.GetApiResourceIdentifier(clrResource);

            var             resourceLinkageKey = new ResourceLinkageKey(fromApiResourceIdentifier, apiRelationshipRel);
            ResourceLinkage resourceLinkage;
            var             hasResourceLinkage = this.DocumentBuilderContext.TryGetResourceLinkage(resourceLinkageKey, out resourceLinkage);

            // .. Meta
            var apiRelationshipMeta = default(Meta);
            var domRelationshipMeta = (IDomMeta)domReadWriteRelationship.GetNode(DomNodeType.Meta);

            if (domRelationshipMeta != null)
            {
                apiRelationshipMeta = domRelationshipMeta.Meta;
            }

            // Create the correct relationship context based on resource linkage (if any).
            RelationshipContext relationshipContext;

            if (hasResourceLinkage)
            {
                var resourceLinkageType = resourceLinkage.Type;
                switch (resourceLinkageType)
                {
                case ResourceLinkageType.ToOneResourceLinkage:
                {
                    var toOneResourceLinkage = resourceLinkage.ToOneResourceLinkage;
                    relationshipContext = new ToOneRelationshipContext(apiRelationshipRel, linkContexts, toOneResourceLinkage, apiRelationshipMeta);
                }
                break;

                case ResourceLinkageType.ToManyResourceLinkage:
                {
                    var toManyResourceLinkage = resourceLinkage.ToManyResourceLinkage;
                    relationshipContext = new ToManyRelationshipContext(apiRelationshipRel, linkContexts, toManyResourceLinkage, apiRelationshipMeta);
                }
                break;

                default:
                {
                    var detail = InfrastructureErrorStrings.InternalErrorExceptionDetailUnknownEnumerationValue
                                 .FormatWith(typeof(ResourceLinkageType).Name, resourceLinkageType);
                    throw new InternalErrorException(detail);
                }
                }
            }
            else
            {
                relationshipContext = new RelationshipContext(apiRelationshipRel, linkContexts, apiRelationshipMeta);
            }

            // Create relationship.
            var apiResourceRelationship = hypermediaAssembler.CreateResourceRelationship(hypermediaContext, resourcePathContext, clrResourceType, clrResource, relationshipContext);

            // Replace the old DOM read-write relationship node with a new DOM read-only relationship created by the framework.
            var domReadOnlyRelationship = DomReadOnlyRelationship.Create(apiRelationshipRel, apiResourceRelationship);

            domReadWriteRelationships.ReplaceNode(domReadWriteRelationship, domReadOnlyRelationship);
        }