Example #1
0
        public static void FromApiResource(this JsonApiCollectionDocument document, IEnumerable data, JsonApiResource apiResource, string baseUrl = null)
        {
            if (data == null)
            {
                return;
            }
            var resourceObjects = new List <JsonApiResourceObject>();

            foreach (var item in data)
            {
                var rObject = new JsonApiResourceObject();
                rObject.FromApiResource(item, apiResource, baseUrl);
                resourceObjects.Add(rObject);
            }
            document.Data = resourceObjects;
            if (!string.IsNullOrWhiteSpace(baseUrl))
            {
                document.Links = new JsonApiLinksObject
                {
                    Self = new JsonApiLink
                    {
                        Href = $"{baseUrl}{apiResource.UrlPath}"
                    }
                };
            }
        }
Example #2
0
        public static void FromApiResource(this JsonApiDocument document, object data, JsonApiResource apiResource, string baseUrl = null)
        {
            switch (data)
            {
            case null:
                return;

            case IEnumerable <object> _:
                throw new Exception("data cannot be a collection");
            }

            var rObject = new JsonApiResourceObject();

            rObject.FromApiResource(data, apiResource, baseUrl);
            document.Data = rObject;
            if (!string.IsNullOrWhiteSpace(baseUrl))
            {
                document.Links = new JsonApiLinksObject
                {
                    Self = new JsonApiLink
                    {
                        Href = $"{baseUrl}{apiResource.UrlPath}/{rObject.Id}"
                    }
                };
            }
        }
Example #3
0
 internal static void FromApiResource(this JsonApiResourceObject resourceObject, object data, JsonApiResource apiResource, string baseUrl)
 {
     resourceObject.SetIdAndType(data, apiResource);
     if (apiResource?.Attributes != null)
     {
         foreach (var attr in apiResource.Attributes)
         {
             resourceObject.AddAttribute(data, attr);
         }
     }
     if (apiResource?.Relationships != null)
     {
         foreach (var realtionship in apiResource.Relationships)
         {
             if (realtionship.Kind == RelationshipKind.BelongsTo)
             {
                 resourceObject.AddToOneRelationship(data, apiResource, realtionship, baseUrl);
             }
             else
             {
                 resourceObject.AddToManyRelationship(data, apiResource, realtionship, baseUrl);
             }
         }
     }
     if (!string.IsNullOrWhiteSpace(baseUrl))
     {
         resourceObject.Links = new JsonApiLinksObject
         {
             Self = new JsonApiLink
             {
                 Href = $"{baseUrl}{apiResource.UrlPath}/{resourceObject.Id}"
             }
         };
     }
 }
Example #4
0
        private JsonApiResourceObject GetIncludedResource(ResourceKey includedKey)
        {
            JsonApiResourceObject includedResourceObject = null;

            Included?.ResourceObjectDictionary.TryGetValue(includedKey, out includedResourceObject);
            return(includedResourceObject);
        }
Example #5
0
        /// <summary>
        /// Retrievews a resource from the Dictionary.
        /// Returns null if resource does not exist.
        /// </summary>
        /// <param name="resourceId"></param>
        /// <param name="resourceType"></param>
        /// <returns></returns>
        public JsonApiResourceObject GetResource(string resourceId, string resourceType)
        {
            var key = new ResourceKey(resourceId, resourceType);
            JsonApiResourceObject result = null;

            ResourceObjectDictionary.TryGetValue(key, out result);
            return(result);
        }
Example #6
0
        private JsonApiResourceObject GetIncludedResource(JsonApiResourceIdentifierObject resource)
        {
            var includedKey = new ResourceKey(resource.Id, resource.Type);
            JsonApiResourceObject includedResourceObject = null;

            Included?.ResourceObjectDictionary.TryGetValue(includedKey, out includedResourceObject);
            return(includedResourceObject);
        }
Example #7
0
        private static void ProcessIncludeTree(IJsonApiDocument document, IncludePathNode includePathTree, object data, string baseUrl)
        {
            var relationship = includePathTree.IncludeApiResourceRelationship;
            var dataType     = data.GetType();
            var propertyInfo = dataType.GetProperty(relationship.PropertyName);

            if (propertyInfo == null)
            {
                throw new Exception($"Property {relationship.PropertyName} does not exist for type {dataType.Name}.");
            }
            var value = propertyInfo.GetValueFast(data);

            if (value == null)
            {
                return;
            }
            if (relationship.Kind == RelationshipKind.BelongsTo)
            {
                var jsonResourceObject = new JsonApiResourceObject();
                jsonResourceObject.FromApiResource(value, relationship.RelatedResource, baseUrl);
                if (document.Included == null)
                {
                    document.Included = new JsonApi.Dictionaries.JsonApiResourceObjectDictionary();
                }
                document.Included.AddResource(jsonResourceObject);
                if (includePathTree.Child != null)
                {
                    // jump down the rabbit hole
                    ProcessIncludeTree(document, includePathTree.Child, value, baseUrl);
                }
            }
            else
            {
                if (value is IEnumerable <object> collection && collection.Any())
                {
                    if (document.Included == null)
                    {
                        document.Included = new JsonApi.Dictionaries.JsonApiResourceObjectDictionary();
                    }
                    foreach (var item in collection)
                    {
                        if (item == null)
                        {
                            continue;
                        }
                        var jsonResourceObject = new JsonApiResourceObject();
                        jsonResourceObject.FromApiResource(item, relationship.RelatedResource, baseUrl);
                        document.Included.AddResource(jsonResourceObject);
                        if (includePathTree.Child != null)
                        {
                            // jump down the rabbit hole
                            ProcessIncludeTree(document, includePathTree.Child, item, baseUrl);
                        }
                    }
                }
            }
        }
Example #8
0
        /// <summary>
        /// Adds a resource to the Dictionary.
        /// Ignores duplicates.
        /// </summary>
        /// <param name="resource"></param>
        public void AddResource(JsonApiResourceObject resource)
        {
            var key = new ResourceKey(resource.Id, resource.Type);

            if (ResourceObjectDictionary.ContainsKey(key))
            {
                return;
            }
            ResourceObjectDictionary.Add(key, resource);
        }
        public void JsonApiResourceObject_ManuallyAddRelations()
        {
            var data = new ModelWithReferences
            {
                Id = Guid.NewGuid().ToString(),
                SingleReference = new ModelWithNoReferences {
                    Id = Guid.NewGuid().ToString()
                },
                CollectionReference = new List <ModelWithNoReferences>
                {
                    new ModelWithNoReferences {
                        Id = Guid.NewGuid().ToString()
                    },
                    new ModelWithNoReferences {
                        Id = Guid.NewGuid().ToString()
                    }
                }
            };
            var resourceObject = new JsonApiResourceObject();

            resourceObject.FromObject(data, false);
            resourceObject.Relationships = new Dictionary <string, JsonApiRelationshipObjectBase>();
            resourceObject.Relationships.Add("single-reference", new JsonApiToOneRelationshipObject {
                Data = new JsonApiResourceIdentifierObject(data.SingleReference.Id, data.SingleReference.GetType().GetJsonApiClassName())
            });
            resourceObject.Relationships.Add("collection-reference", new JsonApiToManyRelationshipObject {
                Data = data.CollectionReference.Select(i => new JsonApiResourceIdentifierObject(i.Id, i.GetType().GetJsonApiClassName())).ToList()
            });

            //resourceObject.Attributes = (data, false, x => x.SingleReference);
            var json         = JsonConvert.SerializeObject(resourceObject, Formatting.Indented);
            var deserialized = JsonConvert.DeserializeObject <JsonApiResourceObject>(json);
            var result       = deserialized.ToObject <ModelWithReferences>();

            Assert.IsTrue(result.SingleReference.Id == data.SingleReference.Id);
            Assert.IsTrue(result.CollectionReference.Count() == data.CollectionReference.Count());
        }
Example #10
0
 /// <summary>
 /// Converts the resource to a object.
 /// </summary>
 /// <typeparam name="T"></typeparam>
 /// <returns></returns>
 public static T ToObject <T>(this JsonApiResourceObject resourceObject, bool processRelations = true) where T : IJsonApiDataModel
 {
     return((T)resourceObject.ToObject(typeof(T), processRelations));
 }
Example #11
0
 public static T_Result ToObject <T_Result, T_Resource>(this JsonApiResourceObject resourceObject) where T_Resource : JsonApiResource
 {
     return((T_Result)resourceObject.ToObject(Activator.CreateInstance <T_Resource>(), typeof(T_Result)));
 }
Example #12
0
 internal static IEnumerable <T> Cast <T>(JsonApiResourceObject data, JsonApiResource apiResource)
 {
     return(new List <T> {
         (T)data.ToObject(apiResource, typeof(T))
     });
 }
Example #13
0
 public static T_Result ToObject <T_Result, T_Resource>(this JsonApiResourceObject resourceObject, T_Resource resource) where T_Resource : JsonApiResource
 {
     return((T_Result)resourceObject.ToObject(resource, typeof(T_Result)));
 }
Example #14
0
        /// <summary>
        /// Attempts to instatiate an object of type <paramref name="targetType"/> with data from <paramref name="resourceObject"/> using the <paramref name="apiResource"/>.
        /// </summary>
        /// <param name="resourceObject"></param>
        /// <param name="apiResource"></param>
        /// <param name="targetType"></param>
        /// <returns></returns>
        public static object ToObject(this JsonApiResourceObject resourceObject, JsonApiResource apiResource, Type targetType)
        {
            var result = Activator.CreateInstance(targetType);

            // extract id
            if (!string.IsNullOrWhiteSpace(resourceObject.Id))
            {
                var idProp = targetType.GetProperty(apiResource.IdProperty);
                if (idProp != null)
                {
                    var idObject = BtbrdCoreIdConverters.ConvertFromString(resourceObject.Id, idProp.PropertyType);
                    idProp.SetValueFast(result, idObject);
                }
            }

            // TODO: better iterate over attributes and relations defined in the apiresource

            // extract attributes
            if (resourceObject.Attributes != null)
            {
                foreach (var attribute in resourceObject.Attributes)
                {
                    var resourceAttribute = apiResource.Attributes.Where(a => a.Name == attribute.Key).FirstOrDefault();
                    if (resourceAttribute == null)
                    {
                        continue;
                    }

                    var targetProperty = targetType.GetProperty(resourceAttribute.PropertyName);
                    if (targetProperty == null)
                    {
                        continue;
                    }

                    // Not handled: ienumerables of datetime,datetimeoffset and nullables

                    var underlying = Nullable.GetUnderlyingType(targetProperty.PropertyType) ?? targetProperty.PropertyType;

                    var value = attribute.Value;
                    if (value != null)
                    {
                        if (underlying == typeof(DateTime))
                        {
                            value = DateTime.Parse(value.ToString());
                        }
                        else if (underlying == typeof(DateTimeOffset))
                        {
                            value = DateTimeOffset.Parse(value.ToString());
                        }
                        else if (underlying.IsEnum)
                        {
                            value = Enum.ToObject(underlying, Convert.ChangeType(value, Enum.GetUnderlyingType(underlying)));
                        }
                        else
                        {
                            value = Convert.ChangeType(value, underlying);
                        }
                    }

                    targetProperty.SetValueFast(result, value);
                }
            }

            // extract relationships
            if (resourceObject.Relationships != null)
            {
                foreach (var relationship in resourceObject.Relationships)
                {
                    var relationResource = apiResource.Relationships.Where(r => r.Name == relationship.Key).FirstOrDefault();
                    if (relationResource == null)
                    {
                        continue;
                    }
                    if (relationResource.Kind == RelationshipKind.BelongsTo)
                    {
                        var relationshipObject = relationship.Value as JsonApiToOneRelationshipObject;
                        if (!string.IsNullOrWhiteSpace(relationshipObject.Data?.Id))
                        {
                            var idProp = targetType.GetProperty(relationResource.IdPropertyName);
                            if (idProp != null)
                            {
                                var idObject = BtbrdCoreIdConverters.ConvertFromString(relationshipObject.Data.Id, idProp.PropertyType);
                                idProp.SetValueFast(result, idObject);
                            }
                        }
                    }
                    else
                    {
                        var idProp = targetType.GetProperty(relationResource.IdPropertyName)
                                     ?? throw new Exception($"{nameof(JsonApiResourceObjectExtensions)}: Could not find relation property {relationResource.IdPropertyName}");

                        // get type of the id (e.g. long, string, ..)
                        Type innerType;
                        if (idProp.PropertyType.IsArray)
                        {
                            innerType = idProp.PropertyType.GetElementType();
                        }
                        else if (idProp.PropertyType.IsNonStringEnumerable())
#if (NET40)
                        { innerType = idProp.PropertyType.GetGenericArguments()[0]; }
#else
                        { innerType = idProp.PropertyType.GenericTypeArguments[0]; }
#endif
                        else
                        {
                            throw new Exception($"{nameof(JsonApiResourceObjectExtensions)}: Trying to read the relation, could not find element-type of type {idProp.PropertyType.FullName}.");
                        }

                        if (!(relationship.Value is JsonApiToManyRelationshipObject relationshipObject))
                        {
                            throw new Exception($"{nameof(JsonApiResourceObjectExtensions)}: Expected a {nameof(JsonApiToManyRelationshipObject)}, found {relationship.Value?.GetType().FullName ?? "null"}");
                        }

                        // create List instance
                        //   get the below defined method GetIdCollection for T=innerType
                        //   and executes it.
                        var instance = (typeof(JsonApiResourceObjectExtensions)
                                        .GetMethod(nameof(GetIdCollection))
                                        ?.MakeGenericMethod(innerType) ?? throw new Exception($"{nameof(JsonApiResourceObjectExtensions)}: Method {nameof(GetIdCollection)} not found."))
                                       .Invoke(null, new object[]
                        {
                            /* IEnumerable<JsonApiResourceIdentifierObject> ids : */ relationshipObject.Data,
                            /* bool makeArray : */ idProp.PropertyType.IsArray
                        });

                        idProp.SetValueFast(result, instance);
                    }
Example #15
0
 public static JsonApiResourceObject FromObject(this JsonApiResourceObject resourceObject, IJsonApiDataModel dataModel, bool automaticallyProcessAllRelations = true)
 {
     return(JsonApiResourceBuilder.Build(dataModel, automaticallyProcessAllRelations));
 }
Example #16
0
        public static JsonApiResourceObject Build(IJsonApiDataModel data, bool processRelations)
        {
            if (data == null)
            {
                throw new Exception("data is null");
            }

            JsonApiResourceObject result = new JsonApiResourceObject();

            result.Id   = data.GetIdAsString();
            result.Type = data.GetJsonApiClassName();

            var classType = data.GetType();

            // sort out properties
            var propertyInfos       = classType.GetProperties();
            var propoertyInfoLookup = propertyInfos.ToLookup(p => GetAttributeGroup(p));

            result.Attributes = new Dictionary <string, object>();
            foreach (var item in propoertyInfoLookup[AttributeGroup.Primitive])
            {
                var value = item.GetValueFast(data);
                if (value == null && item.JsonIsIgnoredIfNull())
                {
                    continue;
                }
                result.Attributes.Add(StringUtils.GetAttributeName(item), value);
            }

            foreach (var item in propoertyInfoLookup[AttributeGroup.PrimitiveCollection])
            {
                var value = item.GetValueFast(data);
                if (value == null && item.JsonIsIgnoredIfNull())
                {
                    continue;
                }
                result.Attributes.Add(StringUtils.GetAttributeName(item), value);
            }

            if (result.Attributes.Count < 1)
            {
                result.Attributes = null;
            }


            if (!processRelations)
            {
                return(result);
            }



            Dictionary <string, RelationShipInfo> relationships = new Dictionary <string, RelationShipInfo>();

            foreach (var item in propoertyInfoLookup[AttributeGroup.Reference])
            {
                var value = item.GetValueFast(data) as IJsonApiDataModel;
                var info  = new RelationShipInfo {
                    RelationshipKey = StringUtils.GetRelationShipName(item), RelationshipType = value.GetJsonApiClassName()
                };
                if (value != null)
                {
                    info.RelationshipIds.Add(value.GetIdAsString());
                }
                relationships.Add(item.Name, info);
            }

            foreach (var item in propoertyInfoLookup[AttributeGroup.ReferenceCollection])
            {
                var value = item.GetValueFast(data) as IEnumerable <IJsonApiDataModel>;
                var info  = new RelationShipInfo
                {
                    RelationshipKey  = StringUtils.GetRelationShipName(item),
                    RelationshipType = item.PropertyType.GetGenericArguments()[0].GetJsonApiClassName()
                };
                if (value != null)
                {
                    foreach (var relation in value)
                    {
                        info.RelationshipIds.Add(relation.GetIdAsString());
                    }
                }
                relationships.Add(item.Name, info);
            }

            foreach (var item in propoertyInfoLookup[AttributeGroup.PrimitiveId])
            {
                var value = item.GetValueFast(data);
                if (value == null)
                {
                    continue;
                }
                RelationShipInfo info = null;
                var idAttr            = item.GetCustomAttribute <JsonApiRelationIdAttribute>();
                if (!relationships.TryGetValue(idAttr.PropertyName, out info))
                {
                    throw new Exception($"no reference found for id backing field {idAttr.PropertyName}");
                }
                info.RelationshipIds.Add(value.ToString());
            }

            foreach (var item in propoertyInfoLookup[AttributeGroup.PrimitiveIdCollection])
            {
                var value = item.GetValueFast(data) as IEnumerable;
                if (value == null)
                {
                    continue;
                }
                RelationShipInfo info = null;
                var idAttr            = item.GetCustomAttribute <JsonApiRelationIdAttribute>();
                if (!relationships.TryGetValue(idAttr.PropertyName, out info))
                {
                    throw new Exception($"no reference found for id backing field {idAttr.PropertyName}");
                }
                foreach (var val in value)
                {
                    info.RelationshipIds.Add(val.ToString());
                }
            }

            result.Relationships = new Dictionary <string, JsonApiRelationshipObjectBase>();

            foreach (var r in relationships)
            {
                if (r.Value.RelationshipIds.Count < 1)
                {
                    continue;
                }
                if (r.Value.RelationshipIds.Count == 1)
                {
                    var relO = new JsonApiToOneRelationshipObject();
                    relO.Data = new JsonApiResourceIdentifierObject {
                        Id = r.Value.RelationshipIds.First(), Type = r.Value.RelationshipType
                    };
                    result.Relationships.Add(r.Value.RelationshipKey, relO);
                }
                else
                {
                    var relO = new JsonApiToManyRelationshipObject();
                    relO.Data = r.Value.RelationshipIds.Select(i => new JsonApiResourceIdentifierObject {
                        Id = i, Type = r.Value.RelationshipType
                    }).ToList();
                    result.Relationships.Add(r.Value.RelationshipKey, relO);
                }
            }
            if (result.Relationships.Count < 1)
            {
                result.Relationships = null;
            }

            return(result);
        }
Example #17
0
        /// <summary>
        /// Converts the resource to a object.
        /// </summary>
        /// <returns></returns>
        public static IJsonApiDataModel ToObject(this JsonApiResourceObject resourceObject, Type t, bool processRelations = true)
        {
            IJsonApiDataModel result = null;

            // try to create object from attributes
            try
            {
                if (resourceObject.Attributes == null)
                {
                    result = Activator.CreateInstance(t) as IJsonApiDataModel;
                }
                else
                {
                    result = JObject.FromObject(resourceObject.Attributes).ToObject(t) as IJsonApiDataModel;
                }
                result.SetIdFromString(resourceObject.Id);
            }
            catch { }
            if (!processRelations || result == null || resourceObject.Relationships == null || resourceObject.Relationships.Count < 1)
            {
                return(result);
            }

            var idPropertyDict = t.GetProperties().Where(p => p.GetCustomAttribute <JsonApiRelationIdAttribute>() != null).ToDictionary(k => k.GetCustomAttribute <JsonApiRelationIdAttribute>().PropertyName, v => v);
            Dictionary <string, PropertyInfo> refPropertyDict = null;
            Dictionary <string, string>       refKeyToName    = null;

            {
                var refProperties = t.GetProperties().Where(p => typeof(IJsonApiDataModel).IsAssignableFrom(p.PropertyType) || typeof(IEnumerable <IJsonApiDataModel>).IsAssignableFrom(p.PropertyType));
                refPropertyDict = refProperties.ToDictionary(k => StringUtils.GetRelationShipName(k), v => v);
                refKeyToName    = refProperties.ToDictionary(k => StringUtils.GetRelationShipName(k), v => v.Name);
            }

            foreach (var relation in resourceObject.Relationships)
            {
                if (refKeyToName.TryGetValue(relation.Key, out var propName))
                {
                    if (idPropertyDict.TryGetValue(propName, out var propertyInfo))
                    {
                        if (propertyInfo.PropertyType is IEnumerable)
                        {
                            var relationConcrete = relation.Value as JsonApiToManyRelationshipObject;
                            if (relationConcrete.Data != null)
                            {
                                propertyInfo.SetValue(result, relationConcrete.Data.Select(r => StringUtils.ConvertId(r.Id, propertyInfo.PropertyType)));
                            }
                        }
                        else
                        {
                            var relationConcrete = relation.Value as JsonApiToOneRelationshipObject;
                            if (relationConcrete.Data != null)
                            {
                                propertyInfo.SetValue(result, StringUtils.ConvertId(relationConcrete.Data.Id, propertyInfo.PropertyType));
                            }
                        }
                    }
                }

                if (refPropertyDict.TryGetValue(relation.Key, out var refInfo))
                {
                    if (refInfo.PropertyType.IsNonStringEnumerable())
                    {
                        var innerType           = refInfo.PropertyType.GenericTypeArguments[0];
                        var constructedListType = typeof(List <>).MakeGenericType(innerType);
                        var collection          = Activator.CreateInstance(constructedListType) as IList;
                        var relationConcrete    = relation.Value as JsonApiToManyRelationshipObject;
                        foreach (var r in relationConcrete.Data)
                        {
                            var item = Activator.CreateInstance(innerType) as IJsonApiDataModel;
                            item.SetIdFromString(r?.Id);
                            collection.Add(item);
                        }
                        refInfo.SetValue(result, collection);
                    }
                    else
                    {
                        var relationConcrete = relation.Value as JsonApiToOneRelationshipObject;
                        var item             = Activator.CreateInstance(refInfo.PropertyType) as IJsonApiDataModel;
                        item.SetIdFromString(relationConcrete.Data.Id);
                        refInfo.SetValue(result, item);
                    }
                }
            }

            return(result);
        }