/// <summary> /// Parcours les relations et appelle les repository correspondant /// </summary> public void SaveRelation() { if (!this._informationRessource.HaveType) { return; } if (this._informationRessource.IsEnum) { return; } object idRessource = AttributeHandling.GetIdProperty(this._informationRessource.TypeRessource).GetValue(this._informationRessource.Ressource); // Parcours des relations foreach (Tuple <PropertyInfo, RelationshipJsonApiAttribute> relation in AttributeRelationsHandling.GetRelationshipProperties(this._informationRessource.TypeRessource)) { //Instantiation de la classe RelationSavingEngine avec son type de ressource Type typeRessource = relation.Item1.PropertyType.IsGenericType ? relation.Item1.PropertyType.GetGenericArguments()[0] : relation.Item1.PropertyType; Type typeEngine = typeof(RelationSavingEngine <>).MakeGenericType(typeRessource); Activator.CreateInstance(typeEngine, new object[] { this._serviceProvider, this._informationRessource, relation.Item1, relation.Item2, idRessource }); } }
private static void FeedProperty(object model, PropertyInfo prop, int depth) { // Récupération du type de la proriété (soit son type direct, soit son type défini dans la propriété "Type" de l'annotation PropertyJsonApi Type typeprop = AttributeHandling.GetTypeProperty(prop); // Si on est autorisé en écriture (si ce n'est pas une readonly) if (prop.CanWrite) { // La liste ayant un traitement spécifique, on va vérifier qu'il s'agit d'une liste et récupérer immédiatement son type Type listType = null; if (prop.PropertyType.GetGenericArguments().Length > 0) { listType = prop.PropertyType.GetGenericArguments()[0]; } //Cas de la génération d'une propriété simple // /!\ les listes sont des types systèmes. Ainsi les List<Interface> auraient pue passerer dans ce test if (Utils.IsTypeSystem(typeprop) && (listType == null || !listType.IsInterface)) { prop.SetValue(model, Feed(typeprop, depth + 1)); } // Si on traite une interface, une classe ou un liste d'interface, alors on passera par la génération de modèle else if (typeprop.IsInterface || typeprop.IsClass || (listType != null && listType.IsInterface)) { FeedPropertyObject(model, prop, depth); } } }
/// <summary> /// Execute on each request /// Convert Json Object in request body to the expected type in the controller action /// </summary> public override void OnActionExecuting(ActionExecutingContext context) { if (AttributeHandling.IsIgnoreJsonApi(((ControllerActionDescriptor)context.ActionDescriptor).MethodInfo, Constants.WAY_READER)) { return; } string parameter_name = context.ActionDescriptor.GetParameterNameJsonApi(); object obj = context.ActionArguments.FirstOrDefault(i => i.Key == parameter_name).Value; if (obj != null) { try { JsonApiService service = context.HttpContext.RequestServices.GetRequiredService <JsonApiService>(); JsonApiReader jsonReader = new JsonApiReader(new StreamReader(context.HttpContext.Request.Body).ReadToEnd(), obj); jsonReader.SetResolver(new ResolverData(context.HttpContext.RequestServices, service.Resolvers)); jsonReader.SetConstraintId(context.ActionArguments.FirstOrDefault(i => i.Key == context.ActionDescriptor.GetParameterNameIdArgument()).Value, context.HttpContext.Request.Method); context.ActionArguments[parameter_name] = jsonReader.GetModel(); } catch (JsonApiException ex) { context.HttpContext.Response.StatusCode = Constants.ERROR_STATUT_JSONAPI; context.Result = new ObjectResult(ex.Error.GetJsonErrors()); } } base.OnActionExecuting(context); }
public ImmutableOptions(DeclarationHandling declarationHandling, TextNodeHandling textNodeHandling, AttributeHandling attributeHandling, CommentHandling commentHandling, ProcessingInstructionHandling processingInstructionHandling) { DeclarationHandling = declarationHandling; TextNodeHandling = textNodeHandling; AttributeHandling = attributeHandling; CommentHandling = commentHandling; ProcessingInstructionHandling = processingInstructionHandling; }
/// <summary> /// Récupere la liste des champs donnés dans la Query String pour un type de modele /// Si des "include" sont demandés, les champs clés des relations sont ajoutés également dans la liste des champs /// </summary> public override List <string> GetListeFields(Type type, string relationPath) { IEnumerable <PropertyInfo> relationshipProperties = AttributeRelationsHandling.GetRelationshipProperties(type) .Where(p => Utils.IsRelationInInclude(relationPath + "." + AttributeHandling.GetLabelProperty(p.Item1), this._includes)) .Select(p => p.Item1); return(this.GetListeFieldsFromRelations(type, relationshipProperties)); }
protected PropertyInfo FindSecondaryForeignKeyProperty() { IEnumerable <PropertyInfo> idsProperties = AttributeHandling.GetIdsProperties(typeof(TRessource)); //Si plus de 2 clés primaire, on ne peut pas définir instinctivement la seconde clé étrangere if (idsProperties.Count() > 2) { return(null); } return(idsProperties.FirstOrDefault(prop => prop != this.PrimaryForeigneKeyProperty)); }
private static bool IsSameType(PropertyInfo prop, Type outputType) { Type inType = prop.PropertyType; Type typeprop = AttributeHandling.GetTypeProperty(prop); if (prop.PropertyType.GetGenericArguments().Length > 0) { inType = prop.PropertyType.GetGenericArguments()[0]; typeprop = AttributeHandling.GetTypeProperty(prop).GetGenericArguments()[0]; } return((inType == outputType) || (typeprop == outputType)); }
/// <summary> /// Récupere la liste des champs donnés dans la Query String pour un type de modele /// </summary> /// <returns></returns> public virtual List <string> GetListeFields(Type type) { List <string> fields = this.GetListeFields(AttributeHandling.GetLabelProperty(type)); if (fields != null) { //Récupere les vrais noms des propriétés List <PropertyInfo> fieldsModel = AttributeHandling.GetListeProperties(type, fields).ToList(); fields = fieldsModel.Select(f => f.Name).ToList(); } return(fields); }
/// <summary> /// Récupere une liste d'identifiant qui sera injectée à la classe de criteres /// Dans le cas d'une relation ToOne, la liste d'identifiant contiendra la liste des clés étrangeres /// Dans le cas d'une relation ToMany, la liste d'identifiant contiendra la liste des identifiants des ressources parentes /// </summary> private object GetListeIdentifiant() { PropertyInfo propertyInfo = this._typeRelation == TypeRelation.One ? this._foreignKeyProperty : AttributeHandling.GetIdProperty(this._informationRessource.TypeRessource); Type typeListe = typeof(List <>); Type typeListeGeneric = typeListe.MakeGenericType(propertyInfo.PropertyType); object listeIdentifiant = Activator.CreateInstance(typeListeGeneric); foreach (object ressource in this._informationRessource.RessourceEnum) { typeListeGeneric.GetMethod("Add").Invoke(listeIdentifiant, new object[] { propertyInfo.GetValue(ressource) }); } return(listeIdentifiant); }
private static void CompareAttributes(XElement a, XElement b, AttributeHandling attributeHandling) { var attributesA = a.Attributes(); var attributesB = b.Attributes(); switch (attributeHandling) { case AttributeHandling.Ignore: return; case AttributeHandling.IgnoreMissingInA: CompareSubSets(a, b); return; case AttributeHandling.IgnoreMissingInB: CompareSubSets(b, a); return; case AttributeHandling.IgnoreOrder: CompareSubSets(a, b); CompareSubSets(b, a); return; case AttributeHandling.Strict: if (attributesA.Count() != attributesB.Count()) { throw new UnequalityException(new UnequalityReason("The number of attributes differ.", a, b)); } var aArray = attributesA.ToArray(); var bArray = attributesB.ToArray(); for (var i = 0; i < aArray.Length; i++) { if (!AreEqual(aArray[i], bArray[i])) { throw new UnequalityException(new UnequalityReason($"Attributes at positition {i + 1} differ.", a, b)); } } return; default: throw new UnequalityException(new UnequalityReason("Unexpected")); } }
/// <summary> /// Parcours les relations et effectue pour chacune d'elle une requete de récupération. Les résultats trouvés correspondant sont affectés au relations. /// </summary> /// <param name="depth">Niveau de profondeur de relation transmise récursivement</param> public void BuildRelation(int depth = 0, string baseRelationPath = null) { if (depth >= 5) { return; } if (!this._informationRessource.HaveType) { return; } if (baseRelationPath != null) { baseRelationPath += "."; } // Parcours des relations foreach (Tuple <PropertyInfo, RelationshipJsonApiAttribute> relation in AttributeRelationsHandling.GetRelationshipProperties(this._informationRessource.TypeRessource)) { string relationPath = baseRelationPath + AttributeHandling.GetLabelProperty(relation.Item1); if (!this._queryService.IsInclude(relationPath)) { continue; } //Instantiation de la classe RelationsPropertyEngine avec son type de ressource Type typeEngine = typeof(RelationsPropertyEngine <>).MakeGenericType(relation.Item1.GetPropertyTypeSample()); Activator.CreateInstance(typeEngine, new object[] { this._serviceProvider, this._queryService, this._informationRessource, relation.Item1, relation.Item2, relationPath, depth }); } }
public void Apply(ControllerModel controller) { if (controller.ControllerType.IsGenericType) { // Le parametre généric de la ressource est en premiere position Type primaryRessourceType = controller.ControllerType.GetPrimaryRessourceType(); // Route à appliquer au controller string route; // Cas d'un Controlleur simple if (!controller.ControllerType.IsControllerRelation()) { ControllerJsonApiAttribute controllerAttribute = primaryRessourceType.GetCustomAttribute <ControllerJsonApiAttribute>(); route = controllerAttribute.Route; // Cas d'un Controlleur de relation } else { Type secondaryRessourceType = controller.ControllerType.GetSecondaryRessourceType(); ControllerJsonApiAttribute controllerAttribute = secondaryRessourceType.GetCustomAttribute <ControllerJsonApiAttribute>(); PropertyInfo propertyRelation = secondaryRessourceType.GetProperties().FirstOrDefault(p => p.GetPropertyTypeSample() == primaryRessourceType); if (controllerAttribute == null || propertyRelation == null) { throw new NotImplementedException(); } route = controllerAttribute.Route + "/{id}/" + AttributeHandling.GetLabelProperty(propertyRelation); } controller.Selectors.Clear(); controller.Selectors.Add(new SelectorModel { AttributeRouteModel = new AttributeRouteModel(new RouteAttribute(route)) }); } }
private static void FeedPropertyObject(object modelToBind, PropertyInfo relationship, int depth) { // Récupération du type de la propriété Type typeRelationship = AttributeHandling.GetTypeProperty(relationship); // Génération d'une instance de ce type object tempObj = Activator.CreateInstance(typeRelationship); // Génération d'une liste de modèle if (Utils.IsEnum(tempObj)) { //--------Cas particulier------// //Type spécifié Type sendedType = typeRelationship.GetGenericArguments()[0]; //Type attendu Type waitingType = relationship.PropertyType.GetGenericArguments()[0]; //Instanciation particulière lorsque le type attendu dans le BO est une List<Interface> if (waitingType.GetTypeInfo().IsInterface) { tempObj = Activator.CreateInstance(typeof(List <>).MakeGenericType(waitingType)); } //---------------------------// BindList(sendedType, tempObj, depth); } // Génération d'un modèle simple else { BindModel(typeRelationship, tempObj, depth); } try { relationship.SetValue(modelToBind, tempObj); } catch (Exception) { //On ne bloque pas } }
public RelationsPropertyEngine( IServiceProvider serviceProvider, IQueryService queryService, InformationRessource informationRessource, PropertyInfo propertyRelation, RelationshipJsonApiAttribute relationshipJApiAttribute, string _relationPath, int depth) { this._serviceProvider = serviceProvider; this._queryService = queryService; this._informationRessource = informationRessource; this._relationProperty = propertyRelation; this._relationAttribute = relationshipJApiAttribute; this._depth = depth; this._relationPath = _relationPath; (PropertyInfo foreignKeyProperty, ForeignKeyJsonApiAttribute foreignKeyAttribute) = AttributeRelationsHandling.FindForeignKeyPropertyAndAttribute(this._informationRessource.TypeRessource, this._relationProperty.Name); if (foreignKeyProperty == null && foreignKeyAttribute == null) { throw new JsonApiArchitectureException($"ForeignKeyJsonApi manquant pour {this._relationProperty.Name} dans {this._informationRessource.TypeRessource.Name}, ajouter[ForeignKeyJsonApi (RelationName = nameof({this._relationProperty.Name}))]"); } this._identifiantRelationProperty = AttributeHandling.GetIdProperty(typeof(T)); if (this._identifiantRelationProperty == null) { throw new JsonApiArchitectureException($"Ajouter [IdJsonApi] sur {typeof(T).Name}"); } this._foreignKeyProperty = foreignKeyProperty; this._foreignKeyAttribute = foreignKeyAttribute; this._typeRelation = this._relationAttribute is HasManyJsonApiAttribute ? TypeRelation.Many : TypeRelation.One; this.GetRelations(); }
/// <summary> /// Execute after each action /// Convert return type to jsonAPI format /// </summary> /// <param name="context"></param> public override void OnActionExecuted(ActionExecutedContext context) { if (AttributeHandling.IsIgnoreJsonApi(((ControllerActionDescriptor)context.ActionDescriptor).MethodInfo, Constants.WAY_PARSER)) { return; } JsonApiService service = context.HttpContext.RequestServices.GetRequiredService <JsonApiService>(); if (service.Error != null && service.Error.HasErrors()) { context.HttpContext.Response.StatusCode = Constants.ERROR_STATUT_JSONAPI; context.Result = new ObjectResult(service.Error.GetJsonErrors()); return; } if (context.Result is ObjectResult) { object result = ((ObjectResult)context.Result).Value; //If result is already JObject, return it without transform if (result?.GetType() == typeof(Newtonsoft.Json.Linq.JObject)) { return; } //Transform result to JsonAPI format JsonApiParser jsonAPIParser = service.Parser; jsonAPIParser.SetResolver(new ResolverData(context.HttpContext.RequestServices, service.Resolvers)); jsonAPIParser.SetModel(result); jsonAPIParser.SetOptionsWithQuery(context.HttpContext.Request.Query); ((ObjectResult)context.Result).Value = jsonAPIParser.GetJson(); } base.OnActionExecuted(context); }
public virtual async Task <IActionResult> UpdateRessource(int id, [IdArgumentJsonApi] int idRelation, TRessource ressource) { new RelationsEngine(this.HttpContext.RequestServices, this._queryService, ressource).SaveRelation(); try { AssignIdsInRessource(ressource, id, idRelation, out PropertyInfo secondaryForeigneKeyProperty); int idTemp = await this._repository.UpdateAsync(ressource); if (AttributeHandling.GetIdsProperties(typeof(TRessource)).Count() == 1) { idRelation = idTemp; } else { idRelation = int.Parse(secondaryForeigneKeyProperty.GetValue(ressource).ToString()); } } catch (NotImplementedException) { return(NotFound()); } return(await this.GetRessource(id, idRelation)); }
private T GetJsonApi <T>(JToken source) where T : new() { var model = new T(); if (source == null) { return(model); } try { var type = new JProperty("type", AttributeHandling.GetLabelProperty(new T().GetType())); var attr = new JProperty("attributes", source); var jobject = new JObject { type, attr }; return((T) new JsonApiReader(jobject.ToString(), model).GetModel(true)); } catch (JsonApiException ex) { ex.Error.GetErrors().ForEach(e => this._jsonapi.Error.Create(e)); throw new ArgumentException($"Query invalid|Element in query string is not in expected format"); } }
/// <summary> /// Définit si un type de modele est présent dans le parametre "include" de la Query String /// </summary> public bool IsInclude <T>() => this.IsInclude(AttributeHandling.GetLabelProperty(typeof(T)));
/// <summary> /// Récuperer l'instance de la classe de critéres à utiliser pour le datasource /// </summary> /// <returns></returns> private object GetCriteres() { Type typeCriteres = this._foreignKeyAttribute.Criteres ?? AttributeRelationsHandling.GetCriteresType(typeof(T)); MethodInfo filterMethod = this._queryService.GetType().GetMethod(nameof(IQueryService.FilterOnInclude)).MakeGenericMethod(typeCriteres); object criteres = filterMethod.Invoke(this._queryService, new object[] { AttributeHandling.GetLabelProperty(this._relationProperty) }); if (this._foreignKeyAttribute.Property == null) { if (this._typeRelation == TypeRelation.Many) { (criteres as ICriteresBase).ListeId = this.GetListeIdentifiantMany().ConvertListObjectToListInt(); } else { (criteres as ICriteresBase).ListeId = this.GetListeIdentifiant().ConvertListObjectToListInt(); } (criteres as ICriteresBase).SkipTake = null; } else { typeCriteres.GetProperty(this._foreignKeyAttribute.Property).SetValue(criteres, this.GetListeIdentifiant()); } return(criteres); }
private void UpdateWithRepository(MethodInfo updateMethod, object repoInstance, object relationValue) { // int idRelation = (updateMethod.Invoke(repoInstance, new object[] { relationValue }) as Task<int>).GetAwaiter().GetResult(); this._foreignKeyProperty.SetValue(this._informationRessource.Ressource, AttributeHandling.GetIdProperty(typeof(T)).GetValue(relationValue)); }