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}" } }; } }
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}" } }; } }
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}" } }; } }
private JsonApiResourceObject GetIncludedResource(ResourceKey includedKey) { JsonApiResourceObject includedResourceObject = null; Included?.ResourceObjectDictionary.TryGetValue(includedKey, out includedResourceObject); return(includedResourceObject); }
/// <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); }
private JsonApiResourceObject GetIncludedResource(JsonApiResourceIdentifierObject resource) { var includedKey = new ResourceKey(resource.Id, resource.Type); JsonApiResourceObject includedResourceObject = null; Included?.ResourceObjectDictionary.TryGetValue(includedKey, out includedResourceObject); return(includedResourceObject); }
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); } } } } }
/// <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()); }
/// <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)); }
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))); }
internal static IEnumerable <T> Cast <T>(JsonApiResourceObject data, JsonApiResource apiResource) { return(new List <T> { (T)data.ToObject(apiResource, typeof(T)) }); }
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))); }
/// <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); }
public static JsonApiResourceObject FromObject(this JsonApiResourceObject resourceObject, IJsonApiDataModel dataModel, bool automaticallyProcessAllRelations = true) { return(JsonApiResourceBuilder.Build(dataModel, automaticallyProcessAllRelations)); }
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); }
/// <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); }