public void Applies_cascading_settings_for_relationship_links(LinkTypes linksInRelationshipAttribute, LinkTypes linksInResourceContext, LinkTypes linksInOptions, LinkTypes expected) { // Arrange var exampleResourceContext = new ResourceContext { PublicName = nameof(ExampleResource), ResourceType = typeof(ExampleResource), RelationshipLinks = linksInResourceContext }; var options = new JsonApiOptions { RelationshipLinks = linksInOptions }; var request = new JsonApiRequest(); var paginationContext = new PaginationContext(); var resourceGraph = new ResourceGraph(exampleResourceContext.AsArray()); var httpContextAccessor = new FakeHttpContextAccessor(); var linkGenerator = new FakeLinkGenerator(); var controllerResourceMapping = new FakeControllerResourceMapping(); var linkBuilder = new LinkBuilder(options, request, paginationContext, resourceGraph, httpContextAccessor, linkGenerator, controllerResourceMapping); var relationship = new HasOneAttribute { Links = linksInRelationshipAttribute }; // Act RelationshipLinks relationshipLinks = linkBuilder.GetRelationshipLinks(relationship, new ExampleResource()); // Assert if (expected == LinkTypes.None) { relationshipLinks.Should().BeNull(); } else { if (expected.HasFlag(LinkTypes.Self)) { relationshipLinks.Self.Should().NotBeNull(); } else { relationshipLinks.Self.Should().BeNull(); } if (expected.HasFlag(LinkTypes.Related)) { relationshipLinks.Related.Should().NotBeNull(); } else { relationshipLinks.Related.Should().BeNull(); } } }
/// <inheritdoc /> public RelationshipLinks GetRelationshipLinks(RelationshipAttribute relationship, IIdentifiable parent) { if (relationship == null) { throw new ArgumentNullException(nameof(relationship)); } if (parent == null) { throw new ArgumentNullException(nameof(parent)); } var parentResourceContext = _provider.GetResourceContext(parent.GetType()); var childNavigation = relationship.PublicName; RelationshipLinks links = null; if (ShouldAddRelationshipLink(parentResourceContext, relationship, LinkTypes.Related)) { links = new RelationshipLinks { Related = GetRelatedRelationshipLink(parentResourceContext.PublicName, parent.StringId, childNavigation) }; } if (ShouldAddRelationshipLink(parentResourceContext, relationship, LinkTypes.Self)) { links ??= new RelationshipLinks(); links.Self = GetSelfRelationshipLink(parentResourceContext.PublicName, parent.StringId, childNavigation); } return(links); }
/// <inheritdoc /> public RelationshipLinks GetRelationshipLinks(RelationshipAttribute relationship, IIdentifiable parent) { ArgumentGuard.NotNull(relationship, nameof(relationship)); ArgumentGuard.NotNull(parent, nameof(parent)); ResourceContext parentResourceContext = _provider.GetResourceContext(parent.GetType()); string childNavigation = relationship.PublicName; RelationshipLinks links = null; if (ShouldAddRelationshipLink(parentResourceContext, relationship, LinkTypes.Related)) { links = new RelationshipLinks { Related = GetRelatedRelationshipLink(parentResourceContext.PublicName, parent.StringId, childNavigation) }; } if (ShouldAddRelationshipLink(parentResourceContext, relationship, LinkTypes.Self)) { links ??= new RelationshipLinks(); links.Self = GetSelfRelationshipLink(parentResourceContext.PublicName, parent.StringId, childNavigation); } return(links); }
protected ResponseSerializer <T> GetResponseSerializer <T>(IEnumerable <IEnumerable <RelationshipAttribute> > inclusionChains = null, Dictionary <string, object> metaDict = null, TopLevelLinks topLinks = null, ResourceLinks resourceLinks = null, RelationshipLinks relationshipLinks = null) where T : class, IIdentifiable { IMetaBuilder meta = GetMetaBuilder(metaDict); ILinkBuilder link = GetLinkBuilder(topLinks, resourceLinks, relationshipLinks); IEnumerable <IQueryConstraintProvider> includeConstraints = GetIncludeConstraints(inclusionChains); IIncludedResourceObjectBuilder includedBuilder = GetIncludedBuilder(); IFieldsToSerialize fieldsToSerialize = GetSerializableFields(); var resourceObjectBuilder = new ResponseResourceObjectBuilder(link, includedBuilder, includeConstraints, ResourceGraph, GetResourceDefinitionAccessor(), GetSerializerSettingsProvider()); return(new ResponseSerializer <T>(meta, link, includedBuilder, fieldsToSerialize, resourceObjectBuilder, new JsonApiOptions())); }
public SerializerTestsSetup() { _dummyTopLevelLinks = new TopLevelLinks { Self = "http://www.dummy.com/dummy-self-link", Next = "http://www.dummy.com/dummy-next-link", Prev = "http://www.dummy.com/dummy-prev-link", First = "http://www.dummy.com/dummy-first-link", Last = "http://www.dummy.com/dummy-last-link" }; _dummyResourceLinks = new ResourceLinks { Self = "http://www.dummy.com/dummy-resource-self-link" }; _dummyRelationshipLinks = new RelationshipLinks { Related = "http://www.dummy.com/dummy-relationship-related-link", Self = "http://www.dummy.com/dummy-relationship-self-link" }; }
/// <inheritdoc/> public RelationshipLinks GetRelationshipLinks(RelationshipAttribute relationship, IIdentifiable parent) { var parentResourceContext = _provider.GetResourceContext(parent.GetType()); var childNavigation = relationship.PublicRelationshipName; RelationshipLinks links = null; if (ShouldAddRelationshipLink(parentResourceContext, relationship, Link.Related)) { links = new RelationshipLinks { Related = GetRelatedRelationshipLink(parentResourceContext.ResourceName, parent.StringId, childNavigation) }; } if (ShouldAddRelationshipLink(parentResourceContext, relationship, Link.Self)) { links ??= new RelationshipLinks(); links.Self = GetSelfRelationshipLink(parentResourceContext.ResourceName, parent.StringId, childNavigation); } return(links); }
/// <summary> /// Builds the values of the relationships object on a resource object. The server serializer only populates the "data" member when the relationship is /// included, and adds links unless these are turned off. This means that if a relationship is not included and links are turned off, the entry would be /// completely empty, ie { }, which is not conform JSON:API spec. In that case we return null which will omit the entry from the output. /// </summary> protected override RelationshipEntry GetRelationshipData(RelationshipAttribute relationship, IIdentifiable resource) { ArgumentGuard.NotNull(relationship, nameof(relationship)); ArgumentGuard.NotNull(resource, nameof(resource)); RelationshipEntry relationshipEntry = null; IReadOnlyCollection <IReadOnlyCollection <RelationshipAttribute> > relationshipChains = GetInclusionChainsStartingWith(relationship); if (Equals(relationship, _requestRelationship) || relationshipChains.Any()) { relationshipEntry = base.GetRelationshipData(relationship, resource); if (relationshipChains.Any() && relationshipEntry.HasResource) { foreach (IReadOnlyCollection <RelationshipAttribute> chain in relationshipChains) { // traverses (recursively) and extracts all (nested) related resources for the current inclusion chain. _includedBuilder.IncludeRelationshipChain(chain, resource); } } } if (!IsRelationshipInSparseFieldSet(relationship)) { return(null); } RelationshipLinks links = _linkBuilder.GetRelationshipLinks(relationship, resource); if (links != null) { // if relationshipLinks should be built for this entry, populate the "links" field. relationshipEntry ??= new RelationshipEntry(); relationshipEntry.Links = links; } // if neither "links" nor "data" was populated, return null, which will omit this entry from the output. // (see the NullValueHandling settings on <see cref="ResourceObject"/>) return(relationshipEntry); }
public static Dictionary <string, IRelationship> CreateRelationships(object objectGraph, string parentId, IResourceMapping resourceMapping, Context context) { var relationships = new Dictionary <string, IRelationship>(); foreach (var linkMapping in resourceMapping.Relationships) { var relationshipName = linkMapping.RelationshipName; var rel = new Relationship(); var relLinks = new RelationshipLinks(); // Generating "self" link if (linkMapping.SelfUrlTemplate != null) { relLinks.Self = GetUrlFromTemplate(context, linkMapping.SelfUrlTemplate, parentId); } if (!linkMapping.IsCollection) { string relatedId = null; object relatedInstance = null; if (linkMapping.RelatedResource != null) { relatedInstance = linkMapping.RelatedResource(objectGraph); if (relatedInstance != null) { relatedId = linkMapping.ResourceMapping.IdGetter(relatedInstance).ToString(); } } if (linkMapping.RelatedResourceId != null && relatedId == null) { var id = linkMapping.RelatedResourceId(objectGraph); if (id != null) { relatedId = id.ToString(); } } // Generating "related" link for to-one relationships if (linkMapping.RelatedUrlTemplate != null && relatedId != null) { relLinks.Related = GetUrlFromTemplate(context, linkMapping.RelatedUrlTemplate, parentId, relatedId.ToString()); } if (linkMapping.InclusionRule != ResourceInclusionRules.ForceOmit) { // Generating resource linkage for to-one relationships if (relatedInstance != null) { rel.Data = new SingleResourceIdentifier { Id = relatedId, Type = context.Configuration.GetMapping(relatedInstance.GetType()).ResourceType // This allows polymorphic (subtyped) resources to be fully represented } } ; else if (relatedId == null || linkMapping.InclusionRule == ResourceInclusionRules.ForceInclude) { rel.Data = new NullResourceIdentifier(); // two-state null case, see NullResourceIdentifier summary } } } else { // Generating "related" link for to-many relationships if (linkMapping.RelatedUrlTemplate != null) { relLinks.Related = GetUrlFromTemplate(context, linkMapping.RelatedUrlTemplate, parentId); } IEnumerable relatedInstance = null; if (linkMapping.RelatedResource != null) { relatedInstance = (IEnumerable)linkMapping.RelatedResource(objectGraph); } // Generating resource linkage for to-many relationships if (linkMapping.InclusionRule == ResourceInclusionRules.ForceInclude && relatedInstance == null) { rel.Data = new MultipleResourceIdentifiers(); } if (linkMapping.InclusionRule != ResourceInclusionRules.ForceOmit && relatedInstance != null) { var idGetter = linkMapping.ResourceMapping.IdGetter; var identifiers = relatedInstance .Cast <object>() .Select(o => new SingleResourceIdentifier { Id = idGetter(o).ToString(), Type = context.Configuration.GetMapping(o.GetType()).ResourceType // This allows polymorphic (subtyped) resources to be fully represented }); rel.Data = new MultipleResourceIdentifiers(identifiers); } // If data is present, count meta attribute is added for convenience if (rel.Data != null) { rel.Meta = new Dictionary <string, string> { { MetaCountAttribute, ((MultipleResourceIdentifiers)rel.Data).Count.ToString() } } } ; } if (relLinks.Self != null || relLinks.Related != null) { rel.Links = relLinks; } if (rel.Data != null || rel.Links != null) { relationships.Add(relationshipName, rel); } } return(relationships.Any() ? relationships : null); }
protected ILinkBuilder GetLinkBuilder(TopLevelLinks top = null, ResourceLinks resource = null, RelationshipLinks relationship = null) { var mock = new Mock <ILinkBuilder>(); mock.Setup(m => m.GetTopLevelLinks()).Returns(top); mock.Setup(m => m.GetResourceLinks(It.IsAny <string>(), It.IsAny <string>())).Returns(resource); mock.Setup(m => m.GetRelationshipLinks(It.IsAny <RelationshipAttribute>(), It.IsAny <IIdentifiable>())).Returns(relationship); return(mock.Object); }
protected ResponseResourceObjectBuilder GetResponseResourceObjectBuilder(List <List <RelationshipAttribute> > inclusionChains = null, ResourceLinks resourceLinks = null, RelationshipLinks relationshipLinks = null) { var link = GetLinkBuilder(null, resourceLinks, relationshipLinks); var includeConstraints = GetIncludeConstraints(inclusionChains); var includedBuilder = GetIncludedBuilder(); return(new ResponseResourceObjectBuilder(link, includedBuilder, includeConstraints, _resourceGraph, GetSerializerSettingsProvider())); }
protected ResponseSerializer <T> GetResponseSerializer <T>(List <List <RelationshipAttribute> > inclusionChains = null, Dictionary <string, object> metaDict = null, TopLevelLinks topLinks = null, ResourceLinks resourceLinks = null, RelationshipLinks relationshipLinks = null) where T : class, IIdentifiable { var meta = GetMetaBuilder <T>(metaDict); var link = GetLinkBuilder(topLinks, resourceLinks, relationshipLinks); var included = GetIncludedRelationships(inclusionChains); var includedBuilder = GetIncludedBuilder(); var fieldsToSerialize = GetSerializableFields(); ResponseResourceObjectBuilder resourceObjectBuilder = new ResponseResourceObjectBuilder(link, includedBuilder, included, _resourceGraph, GetSerializerSettingsProvider()); return(new ResponseSerializer <T>(meta, link, includedBuilder, fieldsToSerialize, resourceObjectBuilder, new JsonApiOptions())); }
protected ResponseResourceObjectBuilder GetResponseResourceObjectBuilder(IEnumerable <IEnumerable <RelationshipAttribute> > inclusionChains = null, ResourceLinks resourceLinks = null, RelationshipLinks relationshipLinks = null) { ILinkBuilder link = GetLinkBuilder(null, resourceLinks, relationshipLinks); IEnumerable <IQueryConstraintProvider> includeConstraints = GetIncludeConstraints(inclusionChains); IIncludedResourceObjectBuilder includedBuilder = GetIncludedBuilder(); return(new ResponseResourceObjectBuilder(link, includedBuilder, includeConstraints, ResourceGraph, GetResourceDefinitionAccessor(), GetSerializerSettingsProvider())); }