public static object GetTypedId(this IIdentifiable identifiable)
        {
            ArgumentGuard.NotNull(identifiable, nameof(identifiable));

            PropertyInfo property = identifiable.GetType().GetProperty(nameof(Identifiable.Id));

            if (property == null)
            {
                throw new InvalidOperationException($"Resource of type '{identifiable.GetType()}' does not have an 'Id' property.");
            }

            return(property.GetValue(identifiable));
        }
Пример #2
0
        private ResourceObject GetIncludedEntity(IIdentifiable entity)
        {
            if (entity == null)
            {
                return(null);
            }

            var contextEntity      = _jsonApiContext.ResourceGraph.GetContextEntity(entity.GetType());
            var resourceDefinition = _scopedServiceProvider.GetService(contextEntity.ResourceType) as IResourceDefinition;

            var data = GetData(contextEntity, entity, resourceDefinition);

            data.Attributes = new Dictionary <string, object>();

            foreach (var attr in contextEntity.Attributes)
            {
                if (attr.InternalAttributeName == nameof(Identifiable.Id))
                {
                    continue;
                }

                data.Attributes.Add(attr.PublicAttributeName, attr.GetValue(entity));
            }

            return(data);
        }
        private ResourceObject TryGetBuiltResourceObjectFor(IIdentifiable resource)
        {
            Type            resourceType    = resource.GetType();
            ResourceContext resourceContext = ResourceContextProvider.GetResourceContext(resourceType);

            return(_included.SingleOrDefault(resourceObject => resourceObject.Type == resourceContext.PublicName && resourceObject.Id == resource.StringId));
        }
Пример #4
0
        private ResourceObject GetIncludedEntity(IIdentifiable entity, RelationshipAttribute relationship)
        {
            if (entity == null)
            {
                return(null);
            }

            var contextEntity      = _jsonApiContext.ResourceGraph.GetContextEntity(entity.GetType());
            var resourceDefinition = _scopedServiceProvider.GetService(contextEntity.ResourceType) as IResourceDefinition;

            var data = GetData(contextEntity, entity, resourceDefinition);

            data.Attributes = new Dictionary <string, object>();

            contextEntity.Attributes.ForEach(attr =>
            {
                var attributeValue = attr.GetValue(entity);
                if (ShouldIncludeAttribute(attr, attributeValue, relationship))
                {
                    data.Attributes.Add(attr.PublicAttributeName, attributeValue);
                }
            });

            return(data);
        }
Пример #5
0
        /// <inheritdoc />
        public virtual ResourceObject Build(IIdentifiable resource, IReadOnlyCollection <AttrAttribute> attributes = null, IReadOnlyCollection <RelationshipAttribute> relationships = null)
        {
            ArgumentGuard.NotNull(resource, nameof(resource));

            var resourceContext = ResourceContextProvider.GetResourceContext(resource.GetType());

            // populating the top-level "type" and "id" members.
            var resourceObject = new ResourceObject {
                Type = resourceContext.PublicName, Id = resource.StringId
            };

            // populating the top-level "attribute" member of a resource object. never include "id" as an attribute
            if (attributes != null)
            {
                var attributesWithoutId = attributes.Where(attr => attr.Property.Name != nameof(Identifiable.Id)).ToArray();
                if (attributesWithoutId.Any())
                {
                    ProcessAttributes(resource, attributesWithoutId, resourceObject);
                }
            }

            // populating the top-level "relationship" member of a resource object.
            if (relationships != null)
            {
                ProcessRelationships(resource, relationships, resourceObject);
            }

            return(resourceObject);
        }
Пример #6
0
        /// <inheritdoc />
        public virtual ResourceObject Build(IIdentifiable resource, IReadOnlyCollection <AttrAttribute> attributes = null, IReadOnlyCollection <RelationshipAttribute> relationships = null)
        {
            if (resource == null)
            {
                throw new ArgumentNullException(nameof(resource));
            }

            var resourceContext = ResourceContextProvider.GetResourceContext(resource.GetType());

            // populating the top-level "type" and "id" members.
            var resourceObject = new ResourceObject {
                Type = resourceContext.PublicName, Id = resource.StringId == string.Empty ? null : resource.StringId
            };

            // populating the top-level "attribute" member of a resource object. never include "id" as an attribute
            if (attributes != null && (attributes = attributes.Where(attr => attr.Property.Name != nameof(Identifiable.Id)).ToArray()).Any())
            {
                ProcessAttributes(resource, attributes, resourceObject);
            }

            // populating the top-level "relationship" member of a resource object.
            if (relationships != null)
            {
                ProcessRelationships(resource, relationships, resourceObject);
            }

            return(resourceObject);
        }
        /// <inheritdoc />
        public string Serialize(IReadOnlyCollection <IIdentifiable> resources)
        {
            if (resources == null)
            {
                throw new ArgumentNullException(nameof(resources));
            }

            IIdentifiable firstResource = resources.FirstOrDefault();

            Document document;

            if (firstResource == null)
            {
                document = Build(resources, Array.Empty <AttrAttribute>(), Array.Empty <RelationshipAttribute>());
            }
            else
            {
                _currentTargetedResource = firstResource.GetType();
                var attributes = GetAttributesToSerialize(firstResource);

                document = Build(resources, attributes, RelationshipsToSerialize);
                _currentTargetedResource = null;
            }

            return(SerializeObject(document, _jsonSerializerSettings));
        }
Пример #8
0
        /// <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);
        }
        /// <summary>
        /// Sets the relationships on a parsed entity
        /// </summary>
        /// <param name="entity">The parsed entity</param>
        /// <param name="relationshipsValues">Relationships and their values, as in the serialized content</param>
        /// <param name="relationshipAttributes">Exposed relationships for <paramref name="entity"/></param>
        /// <returns></returns>
        protected IIdentifiable SetRelationships(IIdentifiable entity, Dictionary <string, RelationshipEntry> relationshipsValues, List <RelationshipAttribute> relationshipAttributes)
        {
            if (relationshipsValues == null || relationshipsValues.Count == 0)
            {
                return(entity);
            }

            var entityProperties = entity.GetType().GetProperties();

            foreach (var attr in relationshipAttributes)
            {
                if (!relationshipsValues.TryGetValue(attr.PublicRelationshipName, out RelationshipEntry relationshipData) || !relationshipData.IsPopulated)
                {
                    continue;
                }

                if (attr is HasOneAttribute hasOneAttribute)
                {
                    SetHasOneRelationship(entity, entityProperties, hasOneAttribute, relationshipData);
                }
                else
                {
                    SetHasManyRelationship(entity, (HasManyAttribute)attr, relationshipData);
                }
            }
            return(entity);
        }
Пример #10
0
        /// <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);
        }
Пример #11
0
 private void DeclareLocalId(IIdentifiable resource)
 {
     if (resource.LocalId != null)
     {
         var resourceContext = _resourceContextProvider.GetResourceContext(resource.GetType());
         _localIdTracker.Declare(resource.LocalId, resourceContext.PublicName);
     }
 }
Пример #12
0
 private void AssertLocalIdIsAssigned(IIdentifiable resource)
 {
     if (resource.LocalId != null)
     {
         var resourceContext = _resourceContextProvider.GetResourceContext(resource.GetType());
         _localIdTracker.GetValue(resource.LocalId, resourceContext.PublicName);
     }
 }
        /// <inheritdoc />
        public void OnSerialize(IIdentifiable resource)
        {
            ArgumentGuard.NotNull(resource, nameof(resource));

            dynamic resourceDefinition = ResolveResourceDefinition(resource.GetType());

            resourceDefinition.OnSerialize((dynamic)resource);
        }
Пример #14
0
        /// <inheritdoc />
        public override ResourceObject Build(IIdentifiable resource, IReadOnlyCollection <AttrAttribute> attributes = null,
                                             IReadOnlyCollection <RelationshipAttribute> relationships = null)
        {
            ResourceObject resourceObject = base.Build(resource, attributes, relationships);

            resourceObject.Meta = _resourceDefinitionAccessor.GetMeta(resource.GetType(), resource);

            return(resourceObject);
        }
Пример #15
0
        /// <summary>
        /// Creates a <see cref="ResourceIdentifierObject"/> from <paramref name="resource"/>.
        /// </summary>
        private ResourceIdentifierObject GetResourceIdentifier(IIdentifiable resource)
        {
            var resourceName = ResourceContextProvider.GetResourceContext(resource.GetType()).PublicName;

            return(new ResourceIdentifierObject
            {
                Type = resourceName,
                Id = resource.StringId
            });
        }
Пример #16
0
        /// <summary>
        /// Creates a <see cref="ResourceIdentifierObject"/> from <paramref name="entity"/>.
        /// </summary>
        private ResourceIdentifierObject GetResourceIdentifier(IIdentifiable entity)
        {
            var resourceName = _provider.GetResourceContext(entity.GetType()).ResourceName;

            return(new ResourceIdentifierObject
            {
                Type = resourceName,
                Id = entity.StringId
            });
        }
Пример #17
0
        /// <summary>
        /// Adds or updates (if already exists) an entity, keyed by type and id.
        /// </summary>
        /// <param name="entity">The item to be added or updated.</param>
        /// <remarks>
        /// Not a thread-safe method.
        /// </remarks>
        internal void AddOrUpdate(IIdentifiable entity)
        {
            Type type = entity.GetType();

            if (!this.supplementalData.ContainsKey(type))
            {
                this.supplementalData.Add(type, new Dictionary <long, IIdentifiable>());
            }

            this.supplementalData[type][entity.Id] = entity;
        }
Пример #18
0
        public Document Build(IIdentifiable entity)
        {
            var contextEntity = _contextGraph.GetContextEntity(entity.GetType());

            var document = new Document
            {
                Data = _getData(contextEntity, entity)
            };

            return(document);
        }
Пример #19
0
        /// <summary>
        /// Checks if the to-one relationship is required by checking if the foreign key is nullable.
        /// </summary>
        private bool IsRequiredToOneRelationship(HasOneAttribute attr, IIdentifiable entity)
        {
            var foreignKey = entity.GetType().GetProperty(attr.IdentifiablePropertyName);

            if (foreignKey != null && Nullable.GetUnderlyingType(foreignKey.PropertyType) == null)
            {
                return(true);
            }

            return(false);
        }
Пример #20
0
        private void AssertTransactional <T>(IIdentifiable <T> item)
        {
            Assert.IsTrue(Factory.IsProxy(item.GetType()));
            Assert.Throws <InvalidOperationException>(() =>
                                                      item.Id = default(T));

            bool detectable = false;

            using (Shield.WhenCommitting <IIdentifiable <T> >(ts => detectable = true))
                Shield.InTransaction(() => item.Id = default(T));
            Assert.IsTrue(detectable);
        }
        /// <summary>
        /// Searches the change tracker for an entity that matches the type and ID of <paramref name="identifiable" />.
        /// </summary>
        public static object GetTrackedIdentifiable(this DbContext dbContext, IIdentifiable identifiable)
        {
            ArgumentGuard.NotNull(dbContext, nameof(dbContext));
            ArgumentGuard.NotNull(identifiable, nameof(identifiable));

            Type   resourceType = identifiable.GetType();
            string stringId     = identifiable.StringId;

            EntityEntry entityEntry = dbContext.ChangeTracker.Entries().FirstOrDefault(entry => IsResource(entry, resourceType, stringId));

            return(entityEntry?.Entity);
        }
        private ResourceObject BuildCachedResourceObjectFor(IIdentifiable resource)
        {
            Type resourceType = resource.GetType();
            IReadOnlyCollection <AttrAttribute>         attributes    = _fieldsToSerialize.GetAttributes(resourceType);
            IReadOnlyCollection <RelationshipAttribute> relationships = _fieldsToSerialize.GetRelationships(resourceType);

            ResourceObject resourceObject = Build(resource, attributes, relationships);

            _included.Add(resourceObject);

            return(resourceObject);
        }
        /// <inheritdoc/>
        public string Serialize(IIdentifiable entity)
        {
            if (entity == null)
            {
                return(JsonConvert.SerializeObject(Build(entity, new List <AttrAttribute>(), new List <RelationshipAttribute>())));
            }

            _currentTargetedResource = entity?.GetType();
            var document = Build(entity, GetAttributesToSerialize(entity), GetRelationshipsToSerialize(entity));

            _currentTargetedResource = null;
            return(JsonConvert.SerializeObject(document));
        }
        /// <summary>
        /// Gets the resource object for <paramref name="parent"/> by searching the included list.
        /// If it was not already build, it is constructed and added to the included list.
        /// </summary>
        /// <param name="parent"></param>
        /// <param name="relationship"></param>
        /// <returns></returns>
        private ResourceObject GetOrBuildResourceObject(IIdentifiable parent, RelationshipAttribute relationship)
        {
            var type         = parent.GetType();
            var resourceName = _provider.GetResourceContext(type).ResourceName;
            var entry        = _included.SingleOrDefault(ro => ro.Type == resourceName && ro.Id == parent.StringId);

            if (entry == null)
            {
                entry = Build(parent, _fieldsToSerialize.GetAllowedAttributes(type, relationship), _fieldsToSerialize.GetAllowedRelationships(type));
                _included.Add(entry);
            }
            return(entry);
        }
Пример #25
0
        /// <summary>
        /// By default, the client serializer does not include any relationships
        /// for resources in the primary data unless explicitly included using
        /// <see cref="RelationshipsToSerialize"/>.
        /// </summary>
        private IReadOnlyCollection <RelationshipAttribute> GetRelationshipsToSerialize(IIdentifiable resource)
        {
            var currentResourceType = resource.GetType();

            // only allow relationship attributes to be serialized if they were set using
            // <see cref="RelationshipsToInclude{T}(Expression{Func{T, dynamic}})"/>
            // and the current resource is a primary entry.
            if (RelationshipsToSerialize == null)
            {
                return(_resourceGraph.GetRelationships(currentResourceType));
            }

            return(RelationshipsToSerialize);
        }
        /// <summary>
        /// By default, the client serializer does not include any relationships
        /// for entities in the primary data unless explicitly included using
        /// <see cref="RelationshipsToSerialize"/>.
        /// </summary>
        private List <RelationshipAttribute> GetRelationshipsToSerialize(IIdentifiable entity)
        {
            var currentResourceType = entity.GetType();

            // only allow relationship attributes to be serialized if they were set using
            // <see cref="RelationshipsToInclude{T}(Expression{Func{T, dynamic}})"/>
            // and the current <paramref name="entity"/> is a main entry in the primary data.
            if (RelationshipsToSerialize == null)
            {
                return(_resourceGraph.GetRelationships(currentResourceType));
            }

            return(RelationshipsToSerialize.ToList());
        }
Пример #27
0
        /// <summary>
        /// Gets the resource object for <paramref name="parent" /> by searching the included list. If it was not already built, it is constructed and added to
        /// the inclusion list.
        /// </summary>
        private ResourceObject GetOrBuildResourceObject(IIdentifiable parent)
        {
            Type           type         = parent.GetType();
            string         resourceName = ResourceContextProvider.GetResourceContext(type).PublicName;
            ResourceObject entry        = _included.SingleOrDefault(ro => ro.Type == resourceName && ro.Id == parent.StringId);

            if (entry == null)
            {
                entry = Build(parent, _fieldsToSerialize.GetAttributes(type), _fieldsToSerialize.GetRelationships(type));
                _included.Add(entry);
            }

            return(entry);
        }
Пример #28
0
        public Document Build(IIdentifiable entity)
        {
            var contextEntity = _contextGraph.GetContextEntity(entity.GetType());

            var document = new Document
            {
                Data  = GetData(contextEntity, entity),
                Meta  = GetMeta(entity),
                Links = _jsonApiContext.PageManager.GetPageLinks(new LinkBuilder(_jsonApiContext))
            };

            document.Included = AppendIncludedObject(document.Included, contextEntity, entity);

            return(document);
        }
        /// <inheritdoc />
        public string Serialize(IIdentifiable resource)
        {
            if (resource == null)
            {
                Document empty = Build((IIdentifiable)null, Array.Empty <AttrAttribute>(), Array.Empty <RelationshipAttribute>());
                return(SerializeObject(empty, _jsonSerializerSettings));
            }

            _currentTargetedResource = resource.GetType();
            Document document = Build(resource, GetAttributesToSerialize(resource), RelationshipsToSerialize);

            _currentTargetedResource = null;

            return(SerializeObject(document, _jsonSerializerSettings));
        }
        /// <inheritdoc/>
        public string Serialize(IIdentifiable entity)
        {
            if (entity == null)
            {
                var empty = Build((IIdentifiable)null, Array.Empty <AttrAttribute>(), Array.Empty <RelationshipAttribute>());
                return(SerializeObject(empty, _jsonSerializerSettings));
            }

            _currentTargetedResource = entity.GetType();
            var document = Build(entity, GetAttributesToSerialize(entity), GetRelationshipsToSerialize(entity));

            _currentTargetedResource = null;

            return(SerializeObject(document, _jsonSerializerSettings));
        }
Пример #31
0
 private IIdentifiable MakeProxy(IIdentifiable source)
 {
     var proxy = IdentifiableProxyBuilder.CreateProxy(source.GetType(), Repository);
     Copy(source, proxy);
     return proxy;
 }