0 sur 1 ont trouvé cela utile - Évaluez ce sujet

Méthodes recommandées : Problèmes de codage courants rencontrés avec le modèle d'objet SharePoint

Résumé : Découvrez les problèmes couramment rencontrés par les développeurs qui écrivent du code personnalisé en utilisant le modèle d'objet SharePoint. (7 pages imprimées)

Scott Harris, Microsoft Corporation

Mike Ammerlaan, Microsoft Corporation

Septembre 2007

S'applique à : Windows SharePoint Services 3.0, Windows SharePoint Services 2.0, Microsoft Office SharePoint Server 2007

Sommaire

Présentation des problèmes courants de codage avec le modèle d'objet SharePoint

Les développeurs sont de plus en plus nombreux à écrire du code personnalisé en utilisant le modèle d'objet SharePoint et ils rencontrent des problèmes courants susceptibles d'affecter les performances des applications. Cet article tente de résoudre certains de ces problèmes et conseille des méthodes pour les identifier et les corriger.

Les domaines suivants reflètent les principaux problèmes rencontrés par les développeurs lorsqu'ils écrivent du code personnalisé en utilisant le modèle d'objet SharePoint :

  • suppression des objets SharePoint ;

  • mise en cache des données et des objets ;

  • écriture d'un code évolutif.

Suppression d'objets SharePoint

L'un des plus grands problèmes qu'un développeur peut rencontrer lorsqu'il écrit du code personnalisé en utilisant le modèle d'objet SharePoint est la suppression incorrecte des objets SharePoint. Les détails du problème de disposition entier pour les objets de SharePoint ne sont pas traités dans cet article ; cependant, nous pouvons fournir ici une méthode pour identifier le problème et des informations générales sur sa correction. Pour plus d'informations sur les méthodes recommandées pour supprimer des objets SharePoint, voir Méthodes recommandées : utilisation d'objets Windows SharePoint Services à supprimer

Dans le modèle d'objet SharePoint, les objets Microsoft.SharePoint.SPSite et Microsoft.SharePoint.SPWeb sont créés dans un code géré sous forme d'un wrapper de faible volume (environ 2 Ko). Ce wrapper crée ensuite des objets non gérés, qui peuvent avoir une taille en moyenne d'environ 1 à 2 Mo. Si votre code ressemble à l'exemple de code suivant, et si vous supposez que la collection SPWeb.WEB compte 10 sous-sites, 10 éléments au total sont créés, chacun représentant une moyenne de 2 Mo de mémoire (pour un total de 20 Mo).

C#
public void GetNavigationInfo()
{
   SPWeb oSPWeb = SPContext.Web;

    // .. Get information oSPWeb for navigation .. 

   foreach(SPWeb oSubWeb in oSPWeb.GetSubWebsForCurrentUser())
   {
      // .. Add subweb information for navigation .. 
    }
}

Quand les charges utilisateurs sont faibles, le scénario précédent peut ne pas présenter de problème. Toutefois, au fur et à mesure que la charge utilisateurs augmente, vous pouvez commencer à constater une baisse de performances, des expirations de délais d'utilisateurs, des erreurs imprévues et, dans certains cas, une défaillance de l'application SharePoint ou du pool d'applications. En utilisant l'exemple précédent de 10 objets créés chaque fois qu'un utilisateur accède à la page, vous pouvez voir comment l'utilisation de la mémoire augmente très rapidement.

Par exemple, le tableau suivant montre le volume de mémoire alloué lorsque des utilisateurs accèdent au système dans une période relativement courte.

Tableau 1. Cas favorable et cas défavorable d'utilisation de la mémoire au fur et à mesure de l'augmentation du nombre d'utilisateurs

Utilisateurs

Cas favorable

Cas défavorable

10

100 Mo

200 Mo

50

500 Mo

1 000 Mo

100

1 000 Mo

2 000 Mo

250

2 500 Mo

5 000 Mo

Cette situation empire avec l'augmentation du nombre d'utilisateurs qui se connectent au système. Au fur et à mesure que l'utilisation de la mémoire augmente, le système commence à se comporter étrangement, notamment à présenter de faibles performances, voire probablement à connaître des défaillances, jusqu'au recyclage du pool d'applications ou de l'émission d'une commande iisreset.

Comment identifier le problème

Vous pouvez facilement identifier ce problème en vous posant les questions suivantes :

  1. Votre pool d'applications se recycle-t-il fréquemment, surtout quand les charges sont élevées ?

    Ceci suppose que le pool d'applications est défini pour se recycler lorsqu'un seuil de mémoire est atteint. Le seuil de mémoire doit être compris entre 800 Mo et 1,5 Go (en supposant que vous avez au moins 2 Go de RAM). La définition du recyclage du pool d'applications à peu près à 1 Go donne les meilleurs résultats, mais vous devez effectuer des essais pour voir quels paramètres fonctionnent le mieux pour votre environnement. Si le paramètre de recyclage est trop bas, vous rencontrerez des problèmes de performances à cause du recyclage fréquent du pool d'applications. Si le paramètre est trop élevé, votre système commencera à présenter des problèmes de performances en raison de l'échange de pages, de la fragmentation de mémoire et d'autres problèmes.

  2. Votre système fonctionne-t-il mal, surtout quand les charges sont élevées ?

    Lorsque l'utilisation de la mémoire commence à augmenter, le système doit compenser, par exemple, en paginant la mémoire et en gérant la fragmentation de mémoire.

  3. Votre système se bloque-t-il ou les utilisateurs rencontrent-ils des erreurs inattendues comme des expirations de délais ou des erreurs de page indisponible, surtout quand les charges sont élevées ?

    En outre, lorsque l'utilisation de mémoire devient élevée ou fragmentée, certaines fonctions peuvent échouer parce qu'elles ne peuvent pas allouer de mémoire pour d'autres opérations. Dans bon nombre de cas, le code ne traite pas convenablement l'exception de « manque de mémoire », qui entraîne des erreurs fausses ou trompeuses.

  4. Votre système utilise-t-il des composants WebPart personnalisés ou utilise des WebPart d'autres fournisseurs ?

    La plupart des développeurs WebPart ne sont pas conscients du fait qu'ils doivent supprimer les objets SharePoint et de la raison pour laquelle ils doivent le faire. Ils supposent que le nettoyage de la mémoire exécute cette fonction automatiquement, mais ce n'est pas vrai dans tous les cas.

Si vous répondez « oui » au numéro 4 et à au moins une des autres questions, il y a environ 90 pourcent de chances que votre code personnalisé ne supprime pas les éléments correctement. Comme vous pouvez le voir dans le Tableau 1, une seule page fortement utilisée qui ne supprime pas correctement les éléments suffit pour causer des problèmes. Voici un exemple de méthode pour réparer la fonction GetNavigationInfo précédente.

C#
public void GetNavigationInfo()
{
   SPWeb oSPWeb = SPContext.Web;

   foreach(SPWeb oSubWeb in oSPWeb.GetSubWebsForCurrentUser()))
   {
      // .. Add subweb information for navigation ..
      oSubWeb.Dispose();
   }
}

Dans la boucle foreach, de nouveaux objets SPWeb sont créés chaque fois qu'ils sont récupérés de la collection. La plupart des développeurs supposent que ces objets sont nettoyés lorsqu'ils n'entrent plus dans l'étendue, mais ce n'est pas le cas quand vous utilisez le modèle d'objet SharePoint.

Vous devez être également conscient d'autres facteurs pouvant causer des problèmes. Par exemple, après avoir appelé la propriété RootWeb sur un site, vous devez supprimer l'objet SPWeb qu'elle crée en appelant la méthode RootWeb.Dispose(). Pour plus d'informations sur la façon de convenablement supprimer des éléments, reportez-vous à Méthodes recommandées : utilisation d'objets Windows SharePoint Services à supprimer.

Remarque Remarque:

Ne supprimez aucun élément retourné directement à partir de la propriété Microsoft.SharePoint.SPContext.Site ou Microsoft.SharePoint.SPContext.Web. Cela pourrait entraîner l'instabilité du système SharePoint et l'échec de l'application.

Mise en cache des données et des objets

De nombreux développeurs commencent à utiliser les objets de cache Microsoft .NET Framework (par exemple, System.Web.Caching.Cache) pour améliorer l'utilisation de la mémoire et augmenter les performances générales du système. Mais, beaucoup d'objets ne sont pas « thread-safe » et leur mise en cache peut provoquer des pannes d'application et des erreurs utilisateur imprévues ou sans rapport.

Mise en cache d'objets SharePoint qui ne sont pas « thread-safe »

Les développeurs essaient d'augmenter les performances et l'utilisation de la mémoire en mettant en cache les objets SPListItemCollection qui sont retournés à partir des requêtes. C'est en général une bonne méthode mais l'objet SPListItemCollection contient un objet SPWeb intégré qui n'est pas « thread-safe » et ne doit pas être mis en cache. Par exemple, supposons que l'objet SPListItemCollection est mis en cache dans le thread A. Quand les autres threads essaient de le lire, l'application peut échouer ou peut se comporter étrangement parce que l'objet n'est pas « thread-safe ».

Pour plus d'informations, reportez-vous à la classe Microsoft.SharePoint.SPWeb.

Ne pas utiliser la synchronisation de threads

Certains développeurs ne sont pas conscients du fait qu'ils opèrent dans un environnement multithreads (par défaut, les services Internet (IIS) sont multithreads) ou de la façon de gérer cet environnement. L'exemple de code suivant montre comment certains développeurs mettent en cache les objets Microsoft.SharePoint.SPListItemCollection.

C#
public void CacheData()
{
   SPListItemCollection oListItems;

   oListItems = (SPListItemCollection)Cache["ListItemCacheName"];
   if(oListItems == null)
   {
      oListItems = DoQueryToReturnItems();
      Cache.Add("ListItemCacheName", oListItems, ..);
   }
}

Dans l'exemple de code précédent, le problème est que si la requête d'obtention des données dure 10 secondes, beaucoup d'utilisateurs peuvent accéder à cette page en même temps et tous exécuter la même requête et essayer de mettre à jour le même objet de cache au même moment. Ceci peut engendrer des problèmes de performances car la même requête pourrait être exécutée 10, 50 ou 100 fois et ceci peut provoquer des incidents parce que plusieurs threads essaient de mettre à jour le même objet au même moment, surtout sur les ordinateurs multiprocessus et avec hyperthreading. Pour résoudre ce problème, vous devez modifier le code comme suit.

C#
public void CacheData()
{
   SPListItemCollection oListItems;

   lock(this)   {
      oListItems = (SPListItemCollection)Cache["ListItemCacheName"];
      if(oListItems == null)
      {
         oListItems = DoQueryToReturnItems();
         Cache.Add("ListItemCacheName", oListItems, ..);
     }
   }
}
Remarque Remarque:

Il est possible d'augmenter légèrement les performances en plaçant le verrou dans le bloc de code if(oListItems == null). Dans ce cas, vous n'avez pas besoin d'interrompre tous les threads pendant que vous vérifiez si les données sont déjà mises en cache. Selon le temps que prend la requête pour retourner les données, il reste toujours possible que plusieurs utilisateurs exécutent la requête au même moment. C'est surtout vrai si vous utilisez des ordinateurs multiprocesseur. N'oubliez pas que le nombre de processeurs en fonctionnement est élevé, plus la requête a besoin de temps pour s'exécuter, et plus il est probable que le placement du verrou dans le bloc de code if() causera des problèmes. Bien que l'exemple précédent puisse causer une légère baisse de performances, c'est le seul moyen de garantir que plusieurs requêtes ne s'exécuteront pas au même moment.

Ce code interrompt tous les autres threads dans une section critique s'exécutant dans Internet Information Services et empêche les autres threads d'accéder à l'objet mis en cache jusqu'à ce qu'il soit généré complètement.

L'exemple précédent adresse le problème de synchronisation de thread ; cependant, il n'est toujours pas optimal parce qu'il met en cache un objet qui n'est pas « thread-safe ». Pour assurer la sûreté des threads, vous mettez en cache un objet DataTable qui est créé à partir de l'objet SPListItemCollection. Par exemple, vous modifiez l'exemple précédent comme suit.

C#
public void CacheData()
{
   DataTable oDataTable;
   SPListItemCollection oListItems;

   lock(this)
   {
      oDataTable = (DataTable)Cache["ListItemCacheName"];
      if(oDataTable == null)
      {
         oListItems = DoQueryToReturnItems();
         oDataTable = oListItems.GetDataTable();
         Cache.Add("ListItemCacheName", oDataTable, ..);
      }
   }
}

Votre code obtient alors les données de l'objet DataTable. Pour plus d'informations et d'exemples d'utilisation de l'objet DataTable et d'autres bonnes idées pour développer des applications SharePoint, consultez les trucs et astuces pour le développement avec Windows SharePoint Services.

Écriture d'un code évolutif

Certains développeurs ne savent pas qu'ils ont besoin d'écrire leur code de sorte qu'il soit évolutif afin de gérer plusieurs utilisateurs en même temps. Un bon exemple en est la création des informations de navigation personnalisée pour tous sites et sous-sites de chaque page ou appartenant à une page maître. Par exemple, si vous avez un site SharePoint sur un réseau intranet d'entreprise et que chaque département a son propre site comprenant de nombreux sous-sites, votre code pourrait ressembler à ce qui suit.

C#
public void GetNavigationInfoForAllSitesAndWebs()
{
   foreach(SPSite oSPSite in SPContext.Current.Site.WebApplication.Sites)
   {
      using(SPWeb oSPWeb  = oSPSite.RootWeb)
      {
         AddAllWebs(oSPWeb );
      }
   }
}
C#
public void AddAllWebs(SPWeb oSPWeb)
{
   foreach(SPWeb oSubWeb in oSPWeb.Webs)
   {
      //.. Code to add items ..
      AddAllWebs(oSubWeb);
      oSubWeb.Dispose();
   }
}

Bien que le code précédent supprime les objets convenablement, il cause toujours des problèmes parce qu'il traverse sans cesse les mêmes listes. Par exemple, si vous avez 10 collections de sites et une moyenne de 20 sites ou sous-sites par collection, vous répétez par itération 200 fois le même code. Pour un petit nombre d'utilisateurs, cela n'entraînera pas forcément de mauvaises performances. Mais, au fur et à mesure de l'ajout d'utilisateurs au système, le problème s'aggrave. Le tableau 2 illustre ceci.

Tableau 2. Les itérations augmentent avec le nombre d'utilisateurs
Utilisateurs Itérations

10

2000

50

10000

100

200000

250

500000

Le code s'exécute pour chaque utilisateur qui accède au système, mais les données restent les mêmes pour tout le monde. L'impact de cette situation peut varier en fonction de ce que fait le code. Dans certains cas, répéter maintes et maintes fois le code peut ne pas provoquer de problème de performances ; cependant, dans l'exemple précédent le système doit créer un objet COM (les objets SPSite ou SPWeb sont créés lorsqu'ils sont récupérés à partir de leurs collections), récupérer des données de l'objet, puis les supprimer pour chaque élément dans la collection. Ceci crée une charge importante.

Comment pouvez-vous rendre ce code plus évolutif, ou adapté pour un environnement à plusieurs utilisateurs ? Il peut être difficile de répondre à cette question, et cela dépend de la fonction prévue pour l'application. Vous devez prendre en compte certains éléments lorsque vous réfléchissez à la manière de rendre un code évolutif :

  • Les données sont-elles statiques (modifications rares), plutôt statiques (modifications de temps en temps) ou dynamiques (modifications en continu) ?

  • Les données sont-elles les mêmes pour tous les utilisateurs, ou changent-elles ? Par exemple, changent-elles en fonction de l'utilisateur qui a ouvert une session, de la partie du site à laquelle il accède ou de la période de l'année (informations saisonnières) ?

  • Les données sont-elles facilement accessibles ou leur restitution prend-elle du temps ? Par exemple, sont-elles retournées à partir d'une requête SQL à exécution longue ou à partir de bases de données distantes qui peuvent présenter une certaine latence réseau dans les transferts de données ?

  • S'agit-il de données publiques ou les données nécessitent-elles un niveau de sécurité plus élevé ?

  • Quelle est la taille des données ?

  • Le site SharePoint se trouve-t-il sur un seul serveur ou sur une batterie de serveurs ?

Selon vos réponses à ces questions, il existe plusieurs méthodes pour rendre votre code plus évolutif et pour gérer de multiples utilisateurs. L'objectif de cet article n'est pas de fournir une réponse à toutes les questions ou scénarios mais de vous donner quelques notions à appliquer à vos besoins spécifiques. Les sections suivantes proposent quelques points à prendre en considération.

Mise en cache des données brutes

Vous mettez en cache vos données en utilisant l'objet System.Web.Caching.Cache. Cet objet nécessite que vous interrogiez les données une fois et que vous les enregistriez dans le cache pour que les autres utilisateurs puissent y accéder.

Si vos données sont statiques, vous pouvez configurer le cache de manière à charger les données et ne pas expirer une avant le redémarrage de l'application ou charger une fois par jour pour garantir l'actualisation des données. Vous pouvez créer l'élément de cache lorsque l'application démarre, lorsque la première session utilisateur démarre ou lorsque le premier utilisateur essaie d'accéder aux données.

Si vos données sont plutôt statiques, vous pouvez configurer les éléments du cache de manière à expirer dans un certain nombre de secondes, de minutes ou d'heures après leur création. Ceci vous permet d'actualiser vos données selon un horaire acceptable pour vos utilisateurs. Même si les données ne sont mises en cache que 30 secondes, quand les charges sont élevées vous verrez toujours une hausse des performances car vous exécutez le code seulement une fois toutes les 30 secondes et non plusieurs fois par seconde, pour chaque utilisateur qui accède au système.

Assurez-vous de prendre en considération les problèmes présentés précédemment dans Mise en cache des données et des objets.

Création de données avant leur affichage

Réfléchissez à la façon dont vos données seront utilisées. Si ces données sont utilisées pour prendre des décisions d'exécution, les placer dans un objet DataSet ou DataTable peut être la meilleure méthode pour les stocker. Vous pouvez ensuite interroger ces objets pour les données pour prendre des décisions d'exécution. Si les données sont utilisées pour afficher une liste, un tableau ou une mise en page à l'utilisateur, envisagez de générer un objet d'affichage et de l'enregistrer dans le cache. Au moment de l'exécution, il vous suffit de récupérer l'objet à partir du cache et d'appeler sa fonction de rendu pour afficher son contenu. Vous pouvez également enregistrer la sortie affichée, mais ceci peut poser des problèmes de sécurité et l'élément mis en cache peut être relativement volumineux, ce qui entraîne un échange de pages important ou une fragmentation de mémoire.

Mise en cache pour un serveur seul ou une batterie de serveurs

Selon la configuration de votre site SharePoint, vous pouvez devoir résoudre différemment certains problèmes de mise en cache. Si vos données doivent constamment être identiques sur tous les serveurs, vous devez vous assurer que les mêmes données sont mises en cache sur chaque serveur. Une méthode pour garantir ceci consiste à créer les données de cache et de les enregistrer sur un serveur commun ou dans une base de données SQL. Une fois encore, vous devez prendre en compte le temps nécessaire pour accéder aux données et les problèmes de sécurité posés si les données sont enregistrées sur un serveur commun.

Vous pouvez créer également des objets de couche d'entreprise qui mettent en cache les données sur un serveur commun, puis accéder à ces données par différentes communications interprocessus disponibles dans les objets de réseau ou les API.

Conclusion

Pour vous assurer que votre système SharePoint fonctionne à son niveau optimal, vous devez pouvoir répondre aux questions suivantes sur le code que vous écrivez :

  • Mon code supprime-t-il correctement les objets SharePoint ?

  • Mon code met-il en cache les objets convenablement ?

  • Mon code met-il en cache les types d'objets corrects ?

  • Mon code utilise-t-il la synchronisation de threads lorsque c'est nécessaire ?

  • Mon code fonctionne-t-il aussi efficacement pour 1 000 utilisateurs que pour 10 utilisateurs ?

Si vous prenez en compte ces points lors de l'écriture de votre code, vous découvrirez que votre système SharePoint fonctionne plus efficacement et que l'expérience de vos utilisateurs est de bien meilleure qualité. Vous pouvez également contribuer à éviter des défaillances et des erreurs inattendues dans votre système.

Remerciements

Nous aimerions remercier les personnes suivantes pour l'aide fantastique qu'ils ont apportée pour les révisions techniques de cet article : James Waymire (Microsoft Corporation), Duray Akar (Microsoft Corporation), Rashid Aga (Microsoft Corporation), Roger Lamb (Microsoft Corporation) et Jeff Lin (Microsoft Corporation).

Ressources supplémentaires

Cela vous a-t-il été utile ?
(1500 caractères restants)
Contenu de la communauté Ajouter
Annotations FAQ