[ASP.NET] Gérer une collection d'objet persistante niveau application

Gérer une collection d'objet persistante niveau application [ASP.NET] - C#/.NET managed - Programmation

Marsh Posté le 06-07-2010 à 17:47:29    

Bonjour à tous.
 
Je suis en train de développer un web service qui va renvoyer une collection d'objet, dont les informations proviennent d'un Active directory.
 
Le temps de récupération de ces informations doivent être le plus rapide possible.
 
Les informations de l'AD varient peu, ainsi il n'est pas nécessaire d'aller chercher les infos a chaque appel.
 
Ainsi j'ai pensé à faire une collection persistante en mémoire qui serait rafraichit toutes les heures.
 
 
Je me pose plusieurs questions:
Ya til des patterns spécifique à .net quand on veux gérer ce genre de collection?
 
 
J'hésite entre 2 manière pour l'instanciation:
 
_Soit dans mon événement Application_Start, je créée et charge la collection, puis je la stocke dans la collection de l'application.
_Soit Je déclare une collection statique dans une classe quelconque, avec un accesseur qui va la construire au premier appel.
 
Je me demande en fait quel est la plus propre, et les avantages / inconvénient de chaque méthode.
 
 
De plus je souhaiterais que le rafraichissement toutes les heures ne se fassent pas au moment de l'appel au la webméthode de récupération de la collection, afin de ne pas pénaliser celui qui fait l'appel au moment ou les 1h se sont écoulées.
 
Quel est la meilleur méthode pour rafraichir cette collection toutes les heures ? un timer créé lors de l'application start ?
 
 
En lisant ça je me rend compte que ça élimine d'office le coup de l'accesseur + collection déclaré statique.
 
 
 
Voilà j'espère ne pas être trop confu, et je suis preneur de toutes remarques  :D


Message édité par ov3rflow le 06-07-2010 à 17:50:23
Reply

Marsh Posté le 06-07-2010 à 17:47:29   

Reply

Marsh Posté le 06-07-2010 à 20:42:32    

Quand tu fais du Webservice tu as accès aux mêmes fonctionnalités que dans une WebApp classique, notamment HttpContextCurrent.Cache, qui offre la possibilité de spécifier la durée de vie des objets lors de leur insertion. Il me semble qu'à l'expiration d'un objet dans le cache tu peux faire lever un événement.

 

Tu peux aussi développer ta propre classe de cache, sous forme de singleton par exemple, qui te fournit les mêmes fonctionnalités. Ca n'est pas bien long à faire si tu n'as besoin que de la mise en cache et de la gestion d'une durée de vie et ça permet d'avoir la main sur le code, d'autant que tu n'as qu'un nombre limité d'infos à manipuler.
Je te le propose également car j'ai déjà eu des surprises très sympas avec la classe Cache de MS. Mon besoin était bcp plus poussé que le tiens mais au final après pas mal de déboires (en grande partie lié à la quantité importante de données manipulées : objets disposés de façon inattendue, bug de concurrence, etc) je me suis résigné à développer ma propre solution, qui en plus m'offrait une meilleure gestion des types via les generics et l'automatisation d'un certain nombre de trucs via la définition d'un Attribute que je venais apposer à chacune de mes classes allant en cache.

 

Dans ce cas attention aux problèmes de concurrence et synchronisation, notamment si plusieurs instances du service tournent en même temps (load balancing, etc). Pense à mettre des lock{} lors des accès à la collection, etc. Tu peux gérer l'expiration de plusieurs façons, plus ou moins simples.


Message édité par TotalRecall le 06-07-2010 à 20:49:41

---------------
Topic .Net - C# @ Prog
Reply

Marsh Posté le 07-07-2010 à 10:50:53    

Merci pour ce retour d'expérience.
 
En fait y'aura beaucoup d'accès pour la lecture, et un seul accès pour l'écriture. Je suppose que le lock, je dois le mettre que la mise à jour de mes objets?
 
Ya effectivement du load balancing, mais sur 2 serveurs physique différent via un alteon, donc je n'aurais pas de pb a ce niveau.
 
 
Je vais donc me tourner vers une classe singleton, dont l'initialisation sera appelé par le Application_Start.
A l'initialisation, je vais utiliser un timer pour appeler une méthode de rechargement.
 
 
 

Reply

Marsh Posté le 07-07-2010 à 17:24:21    

Pas touche au application_start, tu n'en as pas besoin. Instanciation lors de l'appel (respecte le modèle "propre" pour faire du singleton en c#, pas besoin de bricoler un truc exotique).  
Pour le timer dans le framework il y a plusieurs solutions, de mémoire au moins deux, deux classes qui s'appelle Timer toutes les deux, l'une doit se trouver dans System.Timers et l'autre System.Threading. Les deux font à peu près les mêmes trucs, sauf que l'une fonctionne avec une fonction de callback et l'autre un événement. C'est la seule différence notable dont je me souvienne, le reste doit toucher au threading ou la gestion des intervalles (on peut spécifier un délai pour le "start" d'un des deux, et si il se répète ou non je crois).
 
Pour le lock ça dépend de comment tu structures l'appli. Par exemple si tu charges les objets un par un plutôt que la collection complète à chaque fois avant de pouvoir en récupérer un il faut vérifier s'il est déjà dans le cache et sinon le charger et l'y ajouter -> c'est l'ensemble de la procédure qu'il faut enfermer dans un lock dans ce cas, pour s'assurer qu'autre chose à côté ne vas pas également demander l'objet et déclencher la même cascade d'actions.
Attention de ne pas foutre des locks dans tous les coins, ça peut tuer les perfs de l'appli ou créer des deadlocks.  
Il y a des alternatives au lock, par exemple le mot clé volatile ou la classe Interlocked pour les primitifs (je les cite pour info mais personnellement je ne m'en sers jamais).
Le multithreading est une science compliquée (à laquelle je n'ai pas encore compris grand chose d'ailleurs :D), je te conseille de te documenter un peu si le sujet ne t'est pas familier du tout. En Web ça te servira de toute façon.
Un peu de lecture :
http://www.yoda.arachsys.com/cshar [...] ndex.shtml
http://www.albahari.com/threading/part2.aspx
Ce sont des tutos généralistes, tu dois pouvoir trouver des trucs plus spécifiques.


---------------
Topic .Net - C# @ Prog
Reply

Marsh Posté le 07-07-2010 à 17:42:10    

J'ai fait un pattern de singleton "optimisé c#", repompé sur un site.  
 
J'ai simplifié en espérant que ce soit lisible
 

Code :
  1. class DataCache
  2.     {
  3.         private System.Timers.Timer aTimer;
  4.    
  5.         private static readonly DataCache _instance = new DataCache();
  6.         List<SiteInfo> _sites;
  7.         public List<SiteInfo> Sites
  8.         {
  9.             get
  10.             {
  11.                 return _instance._sites;
  12.             }
  13.         }
  14.         public static DataCache GetDatacache()
  15.         {
  16.             return _instance;
  17.         }
  18.         private DataCache()
  19.         {
  20.             _sites = new List<SiteInfo>();
  21.             loadSiteCache(_sites);
  22.             aTimer = new System.Timers.Timer(10000);
  23.             aTimer.Elapsed += new ElapsedEventHandler(ReloadData);
  24.             aTimer.Enabled = true;
  25.         }
  26.         private void loadSiteCache(List<SiteInfo> sites)
  27.         {
  28.             lock (sites)
  29.             {
  30. //Mon code de chargement
  31.             }
  32.         }
  33.         private void ReloadData(object source, ElapsedEventArgs e)
  34.         {
  35.             _instance.loadSiteCache(_instance._sites);
  36.         }


 
 
Effectivement je charge toutes les données en une fois. D'ailleurs je vais optimiser et faire mon lock, qu'a partir du moment ou je vais remplacer la collection en cours.
 
 
Par contre, je veux au moins faire un appel dans le application_Start car je ne veux pas que la personne qui fait le premier appel soit pénalisé, car le temps de chargement peut être très long.  
 
Sauf si tu as mieux a proposer ?
 
 
 
 
Sinon, je vais lire les articles, merci. Et merci pour le reste  :hello:


Message édité par ov3rflow le 07-07-2010 à 17:45:44
Reply

Marsh Posté le 07-07-2010 à 17:52:09    

Tu ne dois pas surtout pas exposer directement la collection à l'extérieur, passe par des méthodes qui interceptent les accès (et profite en pour proposer des méthodes "intelligentes" du genre récupérer truc en fonction de machin)
Effectivement là l'instanciation n'est pas gérée. Pour ta solution du application_start, c'est affreux d'utiliser ça mais si tu ne vois pas d'alternative, tant pis.

 

Remarque perso : GetDataCache() c'est verbeux, si tu n'as pas besoin de paramètre, fais plutôt une propriété, et appelle la Instance.
Tu me remercieras quand tu auras des centaines d'appels au singleton dans ton code :D.

 

Tip : l'instanciation ne doit pas être faite à l'extérieur, le singleton doit se suffire à lui même. L'astuce c'est qu'au premier appel à GetDataCache() (comme tu l'as appelé dans ton cas), si _instance est null on invoque le constructeur du singleton, sinon on renvoie _instance, le tout protégé comme il se doit (lock).
Outre la propreté/cohérence du code, l'avantage c'est que
- si ton application_start fait bien son travail, tant mieux tu auras gagné ça pour le premier utilisateur connecté
- sinon c'est lui qui se tapera l'instanciation, mais tu n'auras pas à gérer ça explicitement, puisque GetDataCache() fait tout.

 

edit : Un petit lien MS sur un modele de singleton : http://msdn.microsoft.com/en-us/library/ff650316.aspx
 

 

En pratique il y a des dizaines de variantes (double lock, lazy/full instanciation, etc), certains se sont même essayés à créer des singleton génériques/dérivables. Mais dans ton cas cet exemple basique ira très bien.


Message édité par TotalRecall le 07-07-2010 à 18:02:29

---------------
Topic .Net - C# @ Prog
Reply

Marsh Posté le 07-07-2010 à 18:01:17    

Je viens de voir que tu fais un new() sur la ligne où tu déclares ton instance, mea culpa.


---------------
Topic .Net - C# @ Prog
Reply

Marsh Posté le 07-07-2010 à 18:06:34    

oui oui l'instanciation se fait bien lors de la première récupération de l'objet:
 

Code :
  1. DataCache cache = DataCache.GetDatacache();


 
Heu du coup attend je relis pour voir ce que je dois faire ou pas.  :D
 
Edit: Et du coup je voulais juste faire cette ligne de code ci dessus dans le App_start pour forcer l'instanciation de l'objet.


Message édité par ov3rflow le 07-07-2010 à 18:07:59
Reply

Marsh Posté le 07-07-2010 à 18:11:53    

Donc sur ton conseil:
 
Je vais renommer GetDataCache, je trouvais ça aussi pourri, mais je n'avais pas meilleure idée, Instance c'est une trés bonne idée.
 
L'accès à ma collection se fera par une méthode et non une propriété.
 


Message édité par ov3rflow le 07-07-2010 à 18:12:27
Reply

Marsh Posté le 07-07-2010 à 18:13:47    

Le post au dessus est un peu bordélique et je l'ai pas mal édité, désolé si tout n'est pas clair :D. N'hésite pas si tu as des questions. Il y a aussi le topic blabla .Net qui peut aider :whistle:

 

edit :

ov3rflow a écrit :

Donc sur ton conseil:
L'accès à ma collection se fera par une méthode et non une propriété.


ba pourquoi :??:

Message cité 1 fois
Message édité par TotalRecall le 07-07-2010 à 18:14:31

---------------
Topic .Net - C# @ Prog
Reply

Marsh Posté le 07-07-2010 à 18:13:47   

Reply

Marsh Posté le 07-07-2010 à 18:16:56    

TotalRecall a écrit :

Le post au dessus est un peu bordélique et je l'ai pas mal édité, désolé si tout n'est pas clair :D. N'hésite pas si tu as des questions. Il y a aussi le topic blabla .Net qui peut aider :whistle:
 
edit :


 


 
 
C'était pas ce que voulais dire cette ligne:
 
Tu ne dois pas surtout pas exposer directement la collection à l'extérieur, passe par des méthodes qui interceptent les accès (et profite en pour proposer des méthodes "intelligentes" du genre récupérer truc en fonction de machin)
 
 
De toute façon, j'ai plusieurs collection à gérer, et certaines vont se faire par des méthodes car je ne reverrai qu'une partie en fonction des paramètres, alors autant tout uniformiser :p

Reply

Marsh Posté le 07-07-2010 à 18:21:39    

Euh je divague, c'est à cause de la phrase au dessus, je croyais que tu disais que ton Instance (pour accéder au singleton) serait une méthode et non une propriété :crazy:


---------------
Topic .Net - C# @ Prog
Reply

Marsh Posté le 07-07-2010 à 18:22:54    

ok :jap:
 
Oui bon je suis pas non plus toujours très clair  :D

Reply

Marsh Posté le 07-07-2010 à 18:43:11    

Non non, je t'en prie, c'est moi :D. A un mot près le sens changeait complètement et c'est la phrase au dessus qui m'a foutu dedans :D.


---------------
Topic .Net - C# @ Prog
Reply

Marsh Posté le 14-07-2010 à 12:32:15    

Hello,
Je ne sais pas où tu en es mais juste pour info je viens de croiser ceci : http://sourceforge.net/projects/gtcache/
http://gtcache.sourceforge.net/doc1.php
Je ne sais pas ce que ça vaut mais c'est toujours bon de partager les infos...


---------------
Topic .Net - C# @ Prog
Reply

Marsh Posté le 15-07-2010 à 15:25:42    

:hello:  
 
Effectivement ça a l'air sympa. Faudrait que je regarde en détail.
 
Mon besoin était assez modeste, donc faudrait voir si c'est pas une usine a gaz  
 
Bon moi de mon coté ce que j'ai fait passe en prod aujourd'hui donc bon  :D  
 
Mais pourquoi pas pou un développement futur

Reply

Sujets relatifs:

Leave a Replay

Make sure you enter the(*)required information where indicate.HTML code is not allowed