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); }
public DocumentPathContextCreateWithUrlAndHypermediaContextTest(IHypermediaContext hypermediaContext, string urlString, IEnumerable <Type> expectedClrResourceTypes, IEnumerable <IHypermediaPath> expectedDocumentSelfPath) { this.HypermediaContext = hypermediaContext; this.UrlString = urlString; this.ExpectedClrResourceTypes = expectedClrResourceTypes; this.ExpectedDocumentSelfPath = expectedDocumentSelfPath; }
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); }
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); }
// 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(); }
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); } }
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); }
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); }
// 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); }
// 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); }