Suppression d’objets
Dernière modification : jeudi 8 avril 2010
S’applique à : SharePoint Foundation 2010
Dans cet article
Introduction à l’utilisation d’objets SharePoint supprimables
Recherche d’objets supprimés de manière incorrecte
Techniques de programmation permettant d’assurer la suppression des objets
Les objets SPSite
Les objets SPWeb
Autres objets devant être supprimés
Conclusion
Introduction à l’utilisation d’objets SharePoint supprimables
Les objets dans les modèles objet Microsoft SharePoint Foundation 2010 et Microsoft SharePoint Server 2010 servent d’interface pour l’utilisation de données SharePoint Foundation. Les développeurs font souvent appel au modèle d’objet pour lire des données ou écrire de nouvelles données dans les banques de données de SharePoint Foundation 2010 et SharePoint Server 2010.
Les modèles objet SharePoint Foundation 2010 et SharePoint Server 2010 contiennent des objets qui implémentent l’interface IDisposable. Vous devez prendre des précautions lors de l’utilisation de ces objets pour éviter leur conservation en mémoire à long terme dans Microsoft .NET Framework.
Plus précisément, vous devez explicitement supprimer les objets SharePoint qui implémentent IDisposable lorsque vous avez terminé de les utiliser.
Dans les scénarios dans lesquels vous utilisez largement des objets SharePoint, par exemple dans des sites SharePoint qui utilisent des composants WebPart personnalisés, vous pouvez provoquer les comportements inhabituels suivants si vous ne supprimez pas les objets SharePoint lorsque vous avez terminé de les utiliser.
Recyclages fréquents du pool d’applications SharePoint Foundation, notamment pendant les périodes d’utilisation maximale
Défaillances d’application qui se traduisent par l’endommagement du tas dans le débogueur
Utilisation élevée de la mémoire pour les processus de traitement des services Internet (IIS)
Faibles performances du système et des applications
Cet article fait office de guide des procédures appropriées de gestion et de suppression des objets SharePoint qui implémentent IDispose. Les problèmes abordés dans cet article sont également signalés par l’outil de vérification de suppression SharePoint (éventuellement en anglais), programme gratuit disponible en téléchargement qui inspecte vos assemblys afin de détecter toute pratique de programmation susceptible d’entraîner des fuites de mémoire en raison de l’utilisation ou de la suppression incorrectes d’objets SharePoint.
Pourquoi les supprimer ?
Plusieurs objets de SharePoint Foundation, principalement les objets de classe de SPSite et de SPWeb, sont créés en tant qu’objets managés. Cependant, ces objets utilisent du code et de la mémoire non managés pour effectuer la majorité de leurs tâches. La partie managée de l’objet est nettement plus petite que la partie non managée. Étant donné que la partie non managée plus petite ne sollicite pas la mémoire du garbage collector, le garbage collector ne libère pas l’objet de la mémoire en temps voulu. L’utilisation d’une grande quantité de mémoire non managée par l’objet peut entraîner les comportement inhabituels décrits ci-dessus. L’appel d’applications utilisant des objets IDisposable de SharePoint Foundation doivent supprimer les objets lorsque l’application a terminé de les utiliser. Vous ne devez pas compter sur le garbage collector pour les libérer de la mémoire automatiquement.
Recherche d’objets supprimés de manière incorrecte
Vous pouvez identifier la présence potentielle d’objets supprimés de manière incorrecte en posant les questions suivantes :
Votre pool d’applications recycle-t-il fréquemment, notamment en cas de surcharges (en supposant que le pool d’applications est configuré pour être recyclé lorsqu’un certain seuil mémoire est atteint) ?
Le seuil mémoire doit être de 800 mégaoctets (Mo) à 1,5 gigaoctet (Go), en supposant au moins 2 Go de RAM. La configuration du recyclage du pool d’applications sur une valeur plus proche de 1 Go produit les meilleurs résultats, mais faites des essais afin de déterminer quels paramètres fonctionnent le mieux avec votre environnement. Si le paramètre de recyclage est trop faible, votre système souffrira de problèmes de performances en raison des recyclages fréquents du pool d’applications. Si le paramètre est trop élevé, votre système sera confronté à des problèmes de performances en raison de la permutation de pages, la fragmentation de mémoire et autres problèmes.
Votre système est-il lent, notamment lorsque la charge est élevée ?
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 la mémoire.
Votre système tombe en panne ou les utilisateurs sont confrontés à des erreurs inattendues telles que des délais d’attente ou des erreurs d’indisponibilité de page, notamment lorsque la charge est élevée ?
À nouveau, lorsque l’utilisation de la mémoire augmente ou devient fragmentée, certaines fonctions échouent car celles-ci ne peuvent pas allouer de la mémoire pour d’autres opérations. Dans de nombreux cas, le code ne gère pas correctement l’exception « mémoire vide », ce qui génère des erreurs fausses ou trompeuses.
Votre système utilise-t-il des composants WebPart tiers ou personnalisés ou des applications personnalisées ?
Vous ne savez peut-être pas que ces composants WebPart doivent supprimer des objets SharePoint et pourquoi, en supposant que le garbage collection exécute cette fonction automatiquement. Toutefois, cela n’est pas vrai dans tous les cas.
Si vous répondez par l’affirmative à la question numéro 4 et à une ou plusieurs des autres questions, il y a fort à parier que votre code personnalisé ne supprime pas correctement les éléments.
Si vos sites présentent l’un des problèmes inhabituels décrits précédemment, vous pouvez déterminer si la cause est une fuite de mémoire en raison d’objets supprimés de manière incorrecte en vérifiant les journaux ULS (disponibles sous C:\Program Files\Common Files\microsoft shared\Web Server Extensions\14\LOGS) pour les entrées liées à l’objet SPRequest. Chaque instance de SPSite et SPWeb contient une référence à un objet SPRequest qui, à son tour, contient une référence à un objet COM non managé qui gère les communications avec le serveur de base de données. SharePoint Foundation surveille le nombre d’objets de SPRequest qui existent dans chaque thread spécifique et les threads parallèles et ajoute des entrées utiles aux journaux dans les trois scénarios suivants :
Le nombre total d’objets de SPRequest dépasse un seuil configurable.
Un objet SPRequest continue d’exister à la fin d’un thread.
Un objet SPRequest a été supprimé du tas par le garbage collection
Le premier scénario est le plus fréquent, notamment si votre site utilise la valeur de seuil par défaut de huit objets SPRequest. Chaque fois que le nombre d’objets de SPRequest dépasse ce seuil, l’entrée suivante apparaît dans les journaux ULS :
« Un nombre potentiellement trop élevé d’objets SPRequest (nombre d’objets) actuellement non libérés sur le thread numéro du thread. Assurez-vous que cet objet ou son parent (tel qu’un objet SPWeb ou SPSite) est correctement supprimé. ID d’allocation de cet objet : {GUID} »
Le meilleur seuil varie selon la nature de votre site et les applications s’exécutant sur celui-ci. Lorsque vos sites rencontrent des problèmes de performances, vous devez surveiller les journaux ULS de votre installation pour comprendre combien d’objets SPRequest créent les applications de votre site. Cela vous permet de déterminer si les conceptions de vos sites et applications créent trop d’objets SPRequest. Même si la suppression incorrecte d’objets n’est pas la cause de votre problème de performances, il se peut que vous deviez revoir la conception de vos sites ou applications de site personnalisées pour réduire la consommation globale de la mémoire résultant de la prolifération excessive d’objets SPRequest.
Étant donné que le seuil par défaut très faible peut ne pas convenir à de nombreux sites, vous pouvez modifier ce seuil en modifiant la sous-clé de Registre suivante :
HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\Shared Tools\Web Server Extensions\HeapSettings
LocalSPRequestWarnCount = valeur de seuil souhaitée
Une fois que vous avez déterminé que la suppression incorrecte d’objets est peut-être à l’origine de la prolifération d’objets de SPRequest et de l’augmentation inutile de l’encombrement mémoire de vos sites, vous pouvez trouver des instances spécifiques de suppression incorrecte en recherchant les deux entrées suivantes. Les deux messages indiquent des cas de gaspillage de mémoire en raison de la suppression incorrecte d’objets SharePoint, et les deux sont liés au nombre et à l’état d’objets SPRequest sur un simple thread :
« Un objet SPRequest n’a pas été supprimé avant la fin de ce thread. Pour éviter de gaspiller des ressources système, supprimez cet objet ou son parent (comme un SPSite ou SPWeb) dès que vous avez terminé de l’utiliser. Cet objet va maintenant être supprimé. ID de allocation : { GUID }Pour déterminer où cet objet a été alloué, créez une sous-clé de Registre sous HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\Shared Tools\Web Server Extensions\HeapSettings. Créez ensuite un nouveau DWORD nommé SPRequestStackTrace avec la valeur 1 sous cette clé. »
Ce message indique qu’un objet SPRequest a été supprimé car il existait toujours à la fin d’un thread.
« Un objet SPRequest a été récupéré par le garbage collector au lieu d’être explicitement libéré. Pour éviter de gaspiller des ressources système, détruisez cet objet ou son parent (comme un SPSite ou SPWeb) dès que vous avez terminé de l’utiliser. ID de répartition : {GUID}Pour déterminer où cet objet a été alloué, créez une clé de Registre sous HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\Shared Tools\Web Server Extensions\HeapSettings. Créez ensuite un nouveau DWORD nommé SPRequestStackTrace avec la valeur 1 sous cette clé. »
Ce message indique que le garbage collector a supprimé un objet SPRequest.
Pour identifier le code à l’origine du problème, vous pouvez rechercher dans les journaux pour les entrées qui contiennent les identificateurs de répartition, ou suivre les instructions dans les avertissements et ajouter le paramètre de sous-clé suivant au Registre :
HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\Shared Tools\Web Server Extensions\HeapSettings SPRequestStackTrace = 1
Ce paramètre de sous-clé garantit que la trace de la pile de la répartition du SPRequest d’origine (qui se produit chaque fois qu’un objet SPSite ou SPWeb est créé) est ajoutée aux journaux lorsque ces avertissements se produisent.
Les sections suivantes décrivent plusieurs techniques de programmation que vous pouvez utiliser pour vous assurer que les objets sont correctement supprimés.
Techniques de programmation permettant d’assurer la suppression des objets
Vous pouvez utiliser certaines techniques de programmation pour vous assurer de la suppression des objets. Ces techniques comprennent l’utilisation des éléments suivants dans votre code :
Méthode Dispose
Instruction using
try, catch, et les blocs finally
Comparaison entre la méthode Dispose et la méthode Close
Les méthodes Dispose et Close pour l’objet SPWeb et l’objet SPSite fonctionnent de la même manière. La méthode Dispose appelle la méthode Close de l’objet. Nous vous recommandons d’appeler la méthode Dispose, plutôt que la méthode Close, car les objets SPWeb et SPSite implémentent l’interface IDisposable et le garbage collection du .NET Framework standard appelle la méthode Dispose pour libérer toute ressource associée à l’objet de la mémoire.
L’instruction using
Vous pouvez automatiquement supprimer les objets SharePoint qui implémentent l’interface IDisposable à l’aide de l’instruction using de Microsoft Visual C# et Visual Basic.
Le code suivant offre un exemple.
String str;
using(SPSite oSPsite = new SPSite("https://server"))
{
using(SPWeb oSPWeb = oSPSite.OpenWeb())
{
str = oSPWeb.Title;
str = oSPWeb.Url;
}
}
Dim str As String
Using oSPsite As New SPSite("https://server")
Using oSPWeb As SPWeb = oSPSite.OpenWeb()
str = oSPWeb.Title
str = oSPWeb.Url
End Using
End Using
Tirer parti des instructions using peut considérablement simplifier votre code. Tel qu’indiqué dans la référence C# (Instruction using), le Common Language Runtime traduit les instructions using en blocs try and finally, et tous les objets qui implémentent l’interface IDisposable sont supprimés à votre place. Toutefois, dans de nombreux cas, les instructions using ne sont pas recommandées, ou doivent être utilisées prudemment et en comprenant le rôle du runtime. L’exemple de code suivant illustre un cas dans lequel vous ne souhaitez pas que le runtime construise un bloc finally et supprime les objets pour vous. Dans ce cas, SPContext renvoie un objet SPWeb.
// Do not do this. Dispose() is automatically called on SPWeb.
using( SPWeb web = SPControl.GetContextWeb(HttpContext.Current)) { ... }
' Do not do this. Dispose() is automatically called on SPWeb.
Using web As SPWeb = SPControl.GetContextWeb(HttpContext.Current)
'.......
End Using
Les objets SPContext sont managés par l’infrastructure SharePoint et doivent être explicitement supprimés de votre code. Cela s’applique également aux objets SPSite et SPWeb renvoyés par SPContext.Site, SPContext.Current.Site, SPContext.Web, et SPContext.Current.Web.
Notes
Cette méthode conseillée résout le problème identifié par l’Outil de vérification de suppression SharePoint (éventuellement en anglais) tel que SPDisposeCheckID_220.
Vous devez toujours être prudent et conscient du rôle du runtime lorsque vous combinez des appels de modèles objet SharePoint sur la même ligne. Les fuites résultant de ce scénario sont parmi les plus difficiles à trouver.
Dans l’exemple de code suivant, un objet SPSite est instancié mais pas supprimé, car le runtime garantit seulement la suppression des objets SPWeb renvoyés par OpenWeb.
void CombiningCallsLeak()
{
using (SPWeb web = new SPSite(SPContext.Current.Web.Url).OpenWeb())
{
// ... New SPSite will be leaked.
} // SPWeb object web.Dispose() automatically called.
}
Private Sub CombiningCallsLeak()
Using web As SPWeb = New SPSite(SPContext.Current.Web.Url).OpenWeb()
' ... New SPSite will be leaked.
End Using ' SPWeb object web.Dispose() automatically called.
End Sub
Vous pouvez résoudre ce problème en imbriquant une instruction using dans une autre.
void CombiningCallsBestPractice()
{
using (SPSite siteCollection = new SPSite(SPContext.Current.Web.Url))
{
using (SPWeb web = siteCollection.OpenWeb())
{
// Perform operations on site.
} // SPWeb object web.Dispose() automatically called.
} // SPSite object siteCollection.Dispose() automatically called.
}
Private Sub CombiningCallsBestPractice()
Using siteCollection As New SPSite(SPContext.Current.Web.Url)
Using web As SPWeb = siteCollection.OpenWeb()
' Perform operations on site.
End Using ' SPWeb object web.Dispose() automatically called.
End Using ' SPSite object siteCollection.Dispose() automatically called.
End Sub
Si vous n’effectuez pas d’opérations sur l’objet SPSite, vous pourriez écrire cela plus succinctement, comme dans l’exemple de code suivant.
void CombiningCallsBestPractice()
{
using (SPSite siteCollection = new SPSite(SPContext.Current.Web.Url))
using (SPWeb web = siteCollection.OpenWeb())
{
// Perform operations on site.
} // SPWeb object web.Dispose() automatically called; SPSite object
// siteCollection.Dispose() automatically called.
}
Private Sub CombiningCallsBestPractice()
Using siteCollection As New SPSite(SPContext.Current.Web.Url)
Using web As SPWeb = siteCollection.OpenWeb()
' Perform operations on site.
End Using ' SPWeb object web.Dispose() automatically called; SPSite object
End Using
' siteCollection.Dispose() automatically called.
End Sub
Dans les autres cas, vous devez construire vos propres blocs try, catch et finally. Les exemples les plus évidents sont des scénarios dans lesquels vous avez besoin de gérer les exceptions, et par conséquent devez inclure des blocs catch. La section suivante fournit des instructions sur où et comment utiliser les blocs try, catch et finally.
Les blocs try, catch et finally
L’utilisation des blocs try, catch et finally est évidemment judicieuse lorsque vous devez gérer des exceptions. Tout code dans un bloc try/catch doit avoir une clause finally régissante, qui garantit la suppression des objets qui implémentent IDisposable. Notez que dans l’exemple de code suivant, vous devez intégrer du code qui gère l’exception dans le bloc catch. Ne laissez jamais un bloc catch vide. Notez également les meilleures méthodes de test pour null avant la suppression.
String str;
SPSite oSPSite = null;
SPWeb oSPWeb = null;
try
{
oSPSite = new SPSite("https://server");
oSPWeb = oSPSite.OpenWeb(..);
str = oSPWeb.Title;
}
catch(Exception e)
{
// Handle exception, log exception, etc.
}
finally
{
if (oSPWeb != null)
oSPWeb.Dispose();
if (oSPSite != null)
oSPSite.Dispose();
}
Dim str As String
Dim oSPSite As SPSite = Nothing
Dim oSPWeb As SPWeb = Nothing
Try
oSPSite = New SPSite("https://server")
oSPWeb = oSPSite.OpenWeb(..)
str = oSPWeb.Title
Catch e As Exception
' Handle exception, log exception, etc.
Finally
If oSPWeb IsNot Nothing Then
oSPWeb.Dispose()
End If
If oSPSite IsNot Nothing Then
oSPSite.Dispose()
End If
End Try
Les blocs Try et finally ou une instruction using seraient nécessaires pour éviter les pertes potentielles lorsque vous créez un objet supprimable dans un bloc foreach, tel qu’illustré dans l’exemple de code suivant.
public static void SPSiteCollectionForEachBestPractice()
{
string sUrl = "http://spvm";
using (SPSite siteCollectionOuter = new SPSite(sUrl))
{
SPWebApplication webApp = siteCollectionOuter.WebApplication;
SPSiteCollection siteCollections = webApp.Sites;
SPSite siteCollectionInner = null;
foreach (siteCollectionInner in siteCollections)
{
try // Should be first statement after foreach.
{
Console.WriteLine(siteCollectionInner.Url);
// Exception occurs here.
}
finally
{
if(siteCollectionInner != null)
siteCollectionInner.Dispose();
}
}
} // SPSite object siteCollectionOuter.Dispose() automatically called.
}
Public Shared Sub SPSiteCollectionForEachBestPractice()
Dim sUrl As String = "http://spvm"
Using siteCollectionOuter As New SPSite(sUrl)
Dim webApp As SPWebApplication = siteCollectionOuter.WebApplication
Dim siteCollections As SPSiteCollection = webApp.Sites
Dim siteCollectionInner As SPSite = Nothing
For Each siteCollectionInner In siteCollections
Try ' Should be first statement after foreach.
Console.WriteLine(siteCollectionInner.Url)
' Exception occurs here.
Finally
If siteCollectionInner IsNot Nothing Then
siteCollectionInner.Dispose()
End If
End Try
Next
End Using
End Sub ' SPSite object siteCollectionOuter.Dispose() automatically called.
Réponse. Redirection avec des blocs try, catch et finally et utilisation d’instructions
Le bloc finally s’exécute après les appels à Response.Redirect dans le bloc try. Response.Redirect génère finalement une exception ThreadAbortException. Lorsque cette exception est levée, le runtime exécute tous les blocs finally avant la fin du thread. Toutefois, étant donné que le bloc finally peut effectuer un calcul indépendant ou annuler le ThreadAbortException, le thread ne se termine pas nécessairement. Par conséquent, vous devez supprimer les objets avant que toute redirection ou transfert de traitement ne puisse avoir lieu. Si votre code doit rediriger, implémentez-le d’une manière similaire à l’exemple de code suivant.
String str;
SPSite oSPSite = null;
SPWeb oSPWeb = null;
try
{
oSPSite = new SPSite("https://server");
oSPWeb = oSPSite.OpenWeb(..);
str = oSPWeb.Title;
if(bDoRedirection)
{
if (oSPWeb != null)
oSPWeb.Dispose();
if (oSPSite != null)
oSPSite.Dispose();
Response.Redirect("newpage.aspx");
}
}
catch(Exception e)
{
}
finally
{
if (oSPWeb != null)
oSPWeb.Dispose();
if (oSPSite != null)
oSPSite.Dispose();
}
Dim str As String
Dim oSPSite As SPSite = Nothing
Dim oSPWeb As SPWeb = Nothing
Try
oSPSite = New SPSite("https://server")
oSPWeb = oSPSite.OpenWeb(..)
str = oSPWeb.Title
If bDoRedirection Then
If oSPWeb IsNot Nothing Then
oSPWeb.Dispose()
End If
If oSPSite IsNot Nothing Then
oSPSite.Dispose()
End If
Response.Redirect("newpage.aspx")
End If
Catch e As Exception
Finally
If oSPWeb IsNot Nothing Then
oSPWeb.Dispose()
End If
If oSPSite IsNot Nothing Then
oSPSite.Dispose()
End If
End Try
Étant donné qu’une instruction using indique au runtime de créer un bloc finally, chaque fois que vous utilisez Response.Redirect dans une instruction using, assurez-vous que les objets sont correctement supprimés. L’exemple de code suivant montre comment vous pouvez procéder.
using (SPSite oSPSite = new SPSite("https://server"))
using (SPWeb oSPWeb = oSPSite.OpenWeb(..))
{
if (bDoRedirection)
Response.Redirect("newpage.aspx");
}
Using oSPSite As New SPSite("https://server")
Using oSPWeb As SPWeb = oSPSite.OpenWeb(..)
If bDoRedirection Then
Response.Redirect("newpage.aspx")
End If
End Using
End Using
Recommandations pour réduire la rétention à long terme d’objets
Vous pouvez réduire la rétention à long terme d’objets SharePoint en suivant ces recommandations d’ordre général.
Si vous créez l’objet avec un opérateur new, vérifiez que l’application de création le supprime.
Notes
Cette méthode conseillée résout le problème identifié par l’Outil de vérification de suppression SharePoint (éventuellement en anglais) tel que SPDisposeCheckID_110.
Bonne pratique de programmation N°1
La suppression explicite
void CreatingSPSiteExplicitDisposeNoLeak() { SPSite siteCollection = null; try { siteCollection = new SPSite("http://moss"); } finally { if (siteCollection != null) siteCollection.Dispose(); } }
Private Sub CreatingSPSiteExplicitDisposeNoLeak() Dim siteCollection As SPSite = Nothing Try siteCollection = New SPSite("http://moss") Finally If siteCollection IsNot Nothing Then siteCollection.Dispose() End If End Try End Sub
Bonne pratique de programmation N° 2
La suppression automatique
CreatingSPSiteWithAutomaticDisposeNoLeak() { using (SPSite siteCollection = new SPSite("http://moss")) { } // SPSite object siteCollection.Dispose() is called automatically. }
CreatingSPSiteWithAutomaticDisposeNoLeak() { using (SPSite siteCollection = new SPSite("http://moss")) { } // SPSite object siteCollection.Dispose() is called automatically. }
Supprimez les éléments créés par les méthodes de SharePoint qui renvoient d’autres objets SPWeb (tels que OpenWeb()).
Notes
Cette méthode conseillée résout le problème identifié par l’Outil de vérification de suppression SharePoint (éventuellement en anglais) tel que SPDisposeCheckID_120.
Bonne pratique de programmation
void OpenWebNoLeak() { using (SPSite siteCollection = new SPSite("http://moss")) { using (SPWeb web = siteCollection.OpenWeb()) { } // SPWeb object web.Dispose() automatically called. } // SPSite object siteCollection.Dispose() automatically called. }
Private Sub OpenWebNoLeak() Using siteCollection As New SPSite("http://moss") Using web As SPWeb = siteCollection.OpenWeb() End Using ' SPWeb object web.Dispose() automatically called. End Using ' SPSite object siteCollection.Dispose() automatically called. End Sub
Ne partagez aucun objet SPRequest (et par extension, aucun objet contenant une référence à un objet SPRequest) sur des threads. Aucune technique de programmation qui partage un objet SPRequest entre deux ou plusieurs threads, ou qui crée un objet SPRequest sur un thread et supprime un autre, n’est prise en charge. Cela signifie que vous ne pouvez pas stocker les objets contenant une référence à un objet SPRequest dans une variable statique. Veuillez ainsi ne pas stocker les objets SharePoint qui implémentent IDisposable (tels que SPWeb ou SPSite) dans des variables statiques.
Les objets SPSite
Cette section décrit des cas de figure dans lesquels des nouveaux objets SPSite sont renvoyés et doivent être supprimés.
En règle générale, lorsqu’une application appelante utilise les nouveaux constructeurs de SPSite (toute signature), elle doit appeler la méthode Dispose() lorsqu’elle a terminé d’utiliser l’objet. Si l’objet SPSite est obtenu à partir de GetContextSite(), l’application appelante ne doit pas supprimer l’objet. Étant donné que les objets SPWeb et SPSite conservent une liste interne qui est dérivée de cette façon, la suppression de l’objet peut entraîner un comportement imprévisible du modèle objet SharePoint. En interne, SharePoint Foundation dresse cette liste une fois l’exécution de la page terminée afin de correctement supprimer les objets.
La classe SPSiteCollection
Cette section décrit les méthodes, les propriétés ou les opérateurs dans l’objet SPSiteCollection qui requièrent la fermeture de l’objet SPSite renvoyé après l’accès.
La méthode SPSiteCollection.Add
La méthode SPSiteCollection.Add crée et renvoie un nouvel objet SPSite. Vous devez supprimer tout objet SPSite renvoyé via la méthode SPSiteCollection.Add.
Notes
Cette méthode conseillée résout le problème identifié par l’Outil de vérification de suppression SharePoint tel que SPDisposeCheckID_240.
Bonne pratique de programmation
void SPSiteCollectionAddLeak()
{
SPWebApplication webApp = new SPSite("http://moss").WebApplication;
SPSiteCollection siteCollections = webApp.Sites;
SPSite siteCollection = siteCollections.Add("sites/myNewSiteCollection", "DOMAIN\\User",
"roger.lamb@litwareinc.com");
// SPSite siteCollection leak.
}
Private Sub SPSiteCollectionAddLeak()
Dim webApp As SPWebApplication = New SPSite("http://moss").WebApplication
Dim siteCollections As SPSiteCollection = webApp.Sites
Dim siteCollection As SPSite = siteCollections.Add("sites/myNewSiteCollection", "DOMAIN\User", "roger.lamb@litwareinc.com")
' SPSite siteCollection leak.
End Sub
Bonne pratique de programmation
void SPSiteCollectionAddNoLeak()
{
SPWebApplication webApp = new SPSite("http://moss").WebApplication;
SPSiteCollection siteCollections = webApp.Sites;
using (SPSite siteCollection = siteCollections.Add("sites/myNewSiteCollection", "DOMAIN\\User",
"roger.lamb@litwareinc.com"))
{
} // SPSite object siteCollection.Dispose() automatically called.
}
Private Sub SPSiteCollectionAddNoLeak()
Dim webApp As SPWebApplication = New SPSite("http://moss").WebApplication
Dim siteCollections As SPSiteCollection = webApp.Sites
Using siteCollection As SPSite = siteCollections.Add("sites/myNewSiteCollection", "DOMAIN\User", "roger.lamb@litwareinc.com")
End Using ' SPSite object siteCollection.Dispose() automatically called.
End Sub
L’opérateur index SPSiteCollection []
L’opérateur index SPSiteCollection [] renvoie un nouvel objet SPSite pour chaque accès. Une instance SPSite est créée même si cet objet a déjà été utilisé. Les exemples de code suivants illustrent une suppression incorrecte de l’objet SPSite.
Notes
Cette méthode conseillée résout le problème identifié par l’Outil de vérification de suppression SharePoint (éventuellement en anglais) tel que SPDisposeCheckID_230.
Mauvaise pratique de programmation n° 1
Utilisation de l’opérateur index
void SPSiteCollectionIndexerLeak()
{
using (SPSite siteCollectionOuter = new SPSite("http://moss"))
{
SPWebApplication webApp = siteCollectionOuter.WebApplication;
SPSiteCollection siteCollections = webApp.Sites;
SPSite siteCollectionInner = siteCollections[0];
// SPSite siteCollectionInner leak.
} // SPSite object siteCollectionOuter.Dispose() automatically called.
}
Private Sub SPSiteCollectionIndexerLeak()
Using siteCollectionOuter As New SPSite("http://moss")
Dim webApp As SPWebApplication = siteCollectionOuter.WebApplication
Dim siteCollections As SPSiteCollection = webApp.Sites
Dim siteCollectionInner As SPSite = siteCollections(0)
' SPSite siteCollectionInner leak.
End Using ' SPSite object siteCollectionOuter.Dispose() automatically called.
End Sub
Bonne pratique de programmation n° 2
Utilisation de la boucle foreach
void SPSiteCollectionForEachLeak()
{
using (SPSite siteCollectionOuter = new SPSite("http://moss"))
{
SPWebApplication webApp = siteCollectionOuter.WebApplication;
SPSiteCollection siteCollections = webApp.Sites;
foreach (SPSite siteCollectionInner in siteCollections)
{
// SPSite siteCollectionInner leak.
}
} // SPSite object siteCollectionOuter.Dispose() automatically called.
}
Private Sub SPSiteCollectionForEachLeak()
Using siteCollectionOuter As New SPSite("http://moss")
Dim webApp As SPWebApplication = siteCollectionOuter.WebApplication
Dim siteCollections As SPSiteCollection = webApp.Sites
For Each siteCollectionInner As SPSite In siteCollections
' SPSite siteCollectionInner leak.
Next siteCollectionInner
End Using ' SPSite object siteCollectionOuter.Dispose() automatically called.
End Sub
Bonne pratique de programmation n° 1
Utilisation de l’opérateur index
void SPSiteCollectionIndexerNoLeak()
{
using (SPSite siteCollectionOuter = new SPSite("http://moss"))
{
SPSite siteCollectionInner = null;
try
{
SPWebApplication webApp = siteCollectionOuter.WebApplication;
SPSiteCollection siteCollections = webApp.Sites;
siteCollectionInner = siteCollections[0];
}
finally
{
if (siteCollectionInner != null)
siteCollectionInner.Dispose();
}
} // SPSite object siteCollectionOuter.Dispose() automatically called.
}
Private Sub SPSiteCollectionIndexerNoLeak()
Using siteCollectionOuter As New SPSite("http://moss")
Dim siteCollectionInner As SPSite = Nothing
Try
Dim webApp As SPWebApplication = siteCollectionOuter.WebApplication
Dim siteCollections As SPSiteCollection = webApp.Sites
siteCollectionInner = siteCollections(0)
Finally
If siteCollectionInner IsNot Nothing Then
siteCollectionInner.Dispose()
End If
End Try
End Using ' SPSite object siteCollectionOuter.Dispose() automatically called.
End Sub
Bonne pratique de programmation n° 2
Utilisation de la boucle foreach
void SPSiteCollectionForEachNoLeak()
{
using (SPSite siteCollectionOuter = new SPSite("http://yoursite”))
{
SPWebApplication webApp = siteCollectionOuter.WebApplication;
SPSiteCollection siteCollections = webApp.Sites;
foreach (SPSite siteCollectionInner in siteCollections)
{
try
{
// ...
}
finally
{
if(siteCollectionInner != null)
siteCollectionInner.Dispose();
}
}
} // SPSite object siteCollectionOuter.Dispose() automatically called.
}
Private Sub SPSiteCollectionForEachNoLeak()
Using siteCollectionOuter As SPSite = New SPSite("http://yoursite")
Dim webApp As SPWebApplication = siteCollectionOuter.WebApplication
Dim siteCollections As SPSiteCollection = webApp.Sites
For Each siteCollectionInner As SPSite In siteCollections
Try
' ...
Finally
If siteCollectionInner IsNot Nothing Then
siteCollectionInner.Dispose()
End If
End Try
Next
End Using
End Sub
La propriété SPSite.AllWebs (SPWebCollection)
Cette section décrit les méthodes, les propriétés ou les opérateurs dans la collection de propriétés AllWebs qui requièrent la fermeture de l’objet SPWeb après l’accès.
La méthode SPSite.AllWebs.Add
La méthode SPSite.AllWebs.Add crée et renvoie un objet SPWeb. Vous devez supprimer tout objet SPWeb renvoyé à partir de SPSite.AllWebs.Add.
Notes
Cette méthode conseillée résout le problème identifié par l’Outil de vérification de suppression SharePoint (éventuellement en anglais) tel que SPDisposeCheckID_150.
Mauvaise pratique de programmation
void AllWebsAddLeak()
{
using (SPSite siteCollection = new SPSite("http://moss"))
{
SPWeb web = siteCollection.AllWebs.Add("site-relative URL");
// SPWeb object leaked.
} // SPSite object siteCollection.Dispose() automatically called.
}
Private Sub AllWebsAddLeak()
Using siteCollection As New SPSite("http://moss")
Dim web As SPWeb = siteCollection.AllWebs.Add("site-relative URL")
' SPWeb object leaked.
End Using ' SPSite object siteCollection.Dispose() automatically called.
End Sub
Bonne pratique de programmation
void AllWebsAddNoLeak()
{
using (SPSite siteCollection = new SPSite("http://moss"))
{
using (SPWeb web = siteCollection.AllWebs.Add("site-relative URL"))
{
} // SPWeb object web.Dispose() automatically called.
} // SPSite object siteCollection.Dispose() automatically called.
}
Private Sub AllWebsAddNoLeak()
Using siteCollection As New SPSite("http://moss")
Using web As SPWeb = siteCollection.AllWebs.Add("site-relative URL")
End Using ' SPWeb object web.Dispose() automatically called.
End Using ' SPSite object siteCollection.Dispose() automatically called.
End Sub
La méthode SPWebCollection.Add
La méthode SPWebCollection.Add crée et renvoie un objet SPWeb qui doit être supprimé.
Notes
Cette méthode conseillée résout le problème identifié par l’Outil de vérification de suppression SharePoint tel que SPDisposeCheckID_200.
Mauvaise pratique de programmation
void SPWebCollectionAddLeak(string strWebUrl)
{
using (SPSite siteCollection = new SPSite("http://moss"))
{
using (SPWeb outerWeb = siteCollection.OpenWeb())
{
SPWebCollection webCollection = siteCollection.AllWebs; // No AllWebs leak just getting reference.
SPWeb innerWeb = webCollection.Add(strWebUrl); // Must dispose innerWeb.
// innerWeb leak.
} // SPWeb object outerWeb.Dispose() automatically called.
} // SPSite object siteCollection.Dispose() automatically called.
}
Private Sub SPWebCollectionAddLeak(ByVal strWebUrl As String)
Using siteCollection As New SPSite("http://moss")
Using outerWeb As SPWeb = siteCollection.OpenWeb()
Dim webCollection As SPWebCollection = siteCollection.AllWebs ' No AllWebs leak just getting reference.
Dim innerWeb As SPWeb = webCollection.Add(strWebUrl) ' Must dispose innerWeb.
' innerWeb leak.
End Using ' SPWeb object outerWeb.Dispose() automatically called.
End Using ' SPSite object siteCollection.Dispose() automatically called.
End Sub
Bonne pratique de programmation
void SPWebCollectionAddNoLeak(string strWebUrl)
{
using (SPSite siteCollection = new SPSite("http://moss"))
{
using (SPWeb outerWeb = siteCollection.OpenWeb())
{
SPWebCollection webCollection = siteCollection.AllWebs; // No AllWebs leak just getting reference.
using (SPWeb innerWeb = webCollection.Add(strWebUrl))
{
//...
}
} // SPWeb object outerWeb.Dispose() automatically called.
} // SPSite object siteCollection.Dispose() automatically called.
}
Private Sub SPWebCollectionAddNoLeak(ByVal strWebUrl As String)
Using siteCollection As New SPSite("http://moss")
Using outerWeb As SPWeb = siteCollection.OpenWeb()
Dim webCollection As SPWebCollection = siteCollection.AllWebs ' No AllWebs leak just getting reference.
Using innerWeb As SPWeb = webCollection.Add(strWebUrl)
'...
End Using
End Using ' SPWeb object outerWeb.Dispose() automatically called.
End Using ' SPSite object siteCollection.Dispose() automatically called.
End Sub
L’opérateur index SPSite.AllWebs []
L’opérateur index SPSite.AllWebs [] renvoie une nouvelle instance SPWeb lors de chaque accès. Un objet est créé au cours de l’opération d’indexation, même si cet objet a déjà été utilisé. S’il n’est pas correctement fermé, les exemples de code suivants laissent un objet SPWeb dans le garbage collector du .NET Framework.
Notes
Cette méthode conseillée résout le problème identifié par l’Outil de vérification de suppression SharePoint tel que SPDisposeCheckID_130.
Mauvaise pratique de programmation
void AllWebsForEachLeak()
{
using (SPSite siteCollection = new SPSite("http://moss"))
{
using (SPWeb outerWeb = siteCollection.OpenWeb())
{
foreach (SPWeb innerWeb in siteCollection.AllWebs)
{
// Explicitly dispose here to avoid out of memory leaks with large number of SPWeb objects.
}
} // SPWeb object outerWeb.Dispose() automatically called.
} // SPSite object siteCollection.Dispose() automatically called.
}
Private Sub AllWebsForEachLeak()
Using siteCollection As New SPSite("http://moss")
Using outerWeb As SPWeb = siteCollection.OpenWeb()
For Each innerWeb As SPWeb In siteCollection.AllWebs
' Explicitly dispose here to avoid out of memory leaks with large number of SPWeb objects.
Next
End Using ' SPWeb object outerWeb.Dispose() automatically called.
End Using ' SPSite object siteCollection.Dispose() automatically called.
End Sub
Bonne pratique de programmation n° 1
Utilisation de la boucle foreach
void AllWebsForEachNoLeakOrMemoryOOM()
{
using (SPSite siteCollection = new SPSite("http://moss"))
{
using (SPWeb outerWeb = siteCollection.OpenWeb())
{
foreach (SPWeb innerWeb in siteCollection.AllWebs)
{
try
{
// ...
}
finally
{
if(innerWeb != null)
innerWeb.Dispose();
}
}
} // SPWeb object outerWeb.Dispose() automatically called.
} // SPSite object siteCollection.Dispose() automatically called.
}
Private Sub AllWebsForEachNoLeakOrMemoryOOM()
Using siteCollection As New SPSite("http://moss")
Using outerWeb As SPWeb = siteCollection.OpenWeb()
For Each innerWeb As SPWeb In siteCollection.AllWebs
Try
' ...
Finally
If innerWeb IsNot Nothing Then
innerWeb.Dispose()
End If
End Try
Next
End Using ' SPWeb object outerWeb.Dispose() automatically called.
End Using ' SPSite object siteCollection.Dispose() automatically called.
End Sub
Bonne pratique de programmation n°2
Utilisation de l’opérateur index
void AllWebsIndexerNoLeak()
{
using (SPSite siteCollection = new SPSite("http://moss"))
{
using (SPWeb web = siteCollection.AllWebs[0])
{
} // SPWeb object web.Dispose() automatically called.
} // SPSite object siteCollection.Dispose() automatically called.
}
Private Sub AllWebsIndexerNoLeak()
Using siteCollection As New SPSite("http://moss")
Using web As SPWeb = siteCollection.AllWebs(0)
End Using ' SPWeb object web.Dispose() automatically called.
End Using ' SPSite object siteCollection.Dispose() automatically called.
End Sub
Les méthodes SPSite.OpenWeb et SPSite. SelfServiceCreateSite
La méthode OpenWeb() et la méthode SelfServiceCreateSite (toutes les signatures) de l’objet SPSite créent un objet SPWeb et le renvoient à l’appelant. Ce nouvel objet n’est pas stocké dans l’objet SPSite et n’est pas supprimé n’importe où dans la classe SPSite. C’est pourquoi vous devez supprimer tout objet créé par le biais de ces méthodes.
Mauvaise pratique de programmation
void OpenWebLeak()
{
using (SPWeb web = new SPSite(SPContext.Current.Web.Url).OpenWeb())
{
// SPSite leaked !
} // SPWeb object web.Dispose() automatically called.
}
Private Sub OpenWebLeak()
Using web As SPWeb = New SPSite(SPContext.Current.Web.Url).OpenWeb()
' SPSite leaked !
End Using ' SPWeb object web.Dispose() automatically called.
End Sub
Bonne pratique de programmation
void OpenWebNoLeak()
{
using (SPSite siteCollection = new SPSite("http://moss"))
{
using (SPWeb web = siteCollection.OpenWeb())
{
} // SPWeb object web.Dispose() automatically called.
} // SPSite object siteCollection.Dispose() automatically called.
}
Private Sub OpenWebNoLeak()
Using siteCollection As New SPSite("http://moss")
Using web As SPWeb = siteCollection.OpenWeb()
End Using ' SPWeb object web.Dispose() automatically called.
End Using ' SPSite object siteCollection.Dispose() automatically called.
End Sub
Propriété SPSite.RootWeb
Les conseils précédents indiquaient que l’application appelante doit supprimer la propriété SPSite.RootWeb juste avant la suppression de l’objet SPSite qui l’utilise. Les conseils officiels ont changé. Le nettoyage de la suppression est automatiquement géré par SharePoint Foundation et SharePoint Server. En outre, les propriétés SPSite, LockIssue, Owner et SecondaryContact ont utilisé les propriétés RootWeb en interne. Étant donné que les conseils ont été mis à jour pour RootWeb, il n’est plus conseillé d’appeler la méthode Dispose sur la propriété SPSite.RootWeb à chaque utilisation de l’une de ces propriétés.
Notes
Cette méthode conseillée résout le problème identifié par l’Outil de vérification de suppression SharePoint tel que SPDisposeCheckID_140.
Bonne pratique de programmation
public void RootWebBestPractice()
{
// New SPSite.
using (SPSite siteCollection = new SPSite("http://moss"))
{
SPWeb rootWeb1 = siteCollection.RootWeb;
// No explicit rootWeb1 dispose required.
} // siteCollection automatically disposed by implementing using().
// rootWeb1 will be Disposed by SPSite.
// SPContext and SPControl
SPWeb rootWeb2 = SPContext.Current.Site.RootWeb;
// Also would apply to SPControl.GetContextSite(Context);
// No explicit rootWeb2 dispose required because it is obtained from SPContext.Current.Site.
}
Public Sub RootWebBestPractice()
' New SPSite.
Using siteCollection As New SPSite("http://moss")
Dim rootWeb1 As SPWeb = siteCollection.RootWeb
' No explicit rootWeb1 dispose required.
End Using ' siteCollection automatically disposed by implementing using().
' rootWeb1 will be Disposed by SPSite.
' SPContext and SPControl
Dim rootWeb2 As SPWeb = SPContext.Current.Site.RootWeb
' Also would apply to SPControl.GetContextSite(Context);
' No explicit rootWeb2 dispose required because it is obtained from SPContext.Current.Site.
End Sub
Microsoft.Office.Server.UserProfiles.PersonalSite (Office SharePoint Server 2007 uniquement)
Microsoft.Office.Server.UserProfiles.PersonalSite renvoie un objet SPSite qui doit être supprimé.
Notes
Cette méthode conseillée résout le problème identifié par l’Outil de vérification de suppression SharePoint tel que SPDisposeCheckID_400.
Mauvaise pratique de programmation
void PersonalSiteLeak()
{
// Open a site collection.
using (SPSite siteCollection = new SPSite("http://moss"))
{
UserProfileManager profileManager = new UserProfileManager(ServerContext.GetContext(siteCollection));
UserProfile profile = profileManager.GetUserProfile("domain\\username");
SPSite personalSite = profile.PersonalSite; // Will leak.
}
}
Private Sub PersonalSiteLeak()
' Open a site collection.
Using siteCollection As New SPSite("http://moss")
Dim profileManager As New UserProfileManager(ServerContext.GetContext(siteCollection))
Dim profile As UserProfile = profileManager.GetUserProfile("domain\username")
Dim personalSite As SPSite = profile.PersonalSite ' Will leak.
End Using
End Sub
Bonne pratique de programmation
void PersonalSiteNoLeak()
{
// Open a site collection.
using (SPSite siteCollection = new SPSite("http://moss"))
{
UserProfileManager profileManager = new UserProfileManager(ServerContext.GetContext(siteCollection));
UserProfile profile = profileManager.GetUserProfile("domain\\username");
using (SPSite personalSite = profile.PersonalSite)
{
// ...
}
}
}
Private Sub PersonalSiteNoLeak()
' Open a site collection.
Using siteCollection As New SPSite("http://moss")
Dim profileManager As New UserProfileManager(ServerContext.GetContext(siteCollection))
Dim profile As UserProfile = profileManager.GetUserProfile("domain\username")
Using personalSite As SPSite = profile.PersonalSite
' ...
End Using
End Using
End Sub
Dans certains cas rares, fuites UserProfiles.PersonalSite telles qu’illustrées dans l’exemple de code suivant.
void PersonalSiteLeak()
{
// Open a site collection.
using (SPSite siteCollection = new SPSite("http://moss"))
{
UserProfileManager profileManager = new UserProfileManager(ServerContext.GetContext(siteCollection));
UserProfile profile = profileManager.GetUserProfile("domain\\username");
SPSite personalSite = profile.PersonalSite; // Will leak.
}
}
Private Sub PersonalSiteLeak()
' Open a site collection.
Using siteCollection As New SPSite("http://moss")
Dim profileManager As New UserProfileManager(ServerContext.GetContext(siteCollection))
Dim profile As UserProfile = profileManager.GetUserProfile("domain\username")
Dim personalSite As SPSite = profile.PersonalSite ' Will leak.
End Using
End Sub
Vous pouvez résoudre ce type de fuites en suivant le modèle illustré dans l’exemple de code suivant.
void PersonalSiteNoLeak()
{
// Open a site collection
using (SPSite siteCollection = new SPSite("http://moss"))
{
UserProfileManager profileManager = new UserProfileManager(ServerContext.GetContext(siteCollection));
UserProfile profile = profileManager.GetUserProfile("domain\\username");
using (SPSite personalSite = profile.PersonalSite)
{
// ...
}
}
}
Private Sub PersonalSiteNoLeak()
' Open a site collection
Using siteCollection As New SPSite("http://moss")
Dim profileManager As New UserProfileManager(ServerContext.GetContext(siteCollection))
Dim profile As UserProfile = profileManager.GetUserProfile("domain\username")
Using personalSite As SPSite = profile.PersonalSite
' ...
End Using
End Using
End Sub
Notez également que vous pouvez améliorer les performances (et éviter de créer un objet SPSite) en récupérant un objet PersonalSite à partir de ProfileLoader, tel qu’illustré dans l’exemple de code suivant.
UserProfile myProfile = ProfileLoader.GetProfileLoader().GetUserProfile();
using (SPSite personalSite = myProfile.PersonalSite)
{
// ...
}
Dim myProfile As UserProfile = ProfileLoader.GetProfileLoader().GetUserProfile()
Using personalSite As SPSite = myProfile.PersonalSite
' ...
End Using
En outre, si vous créez un composant WebPart pour un My Site, vous pouvez utiliser une instance de PersonalSite qui n’a pas besoin d’être supprimée.
IPersonalPage currentMySitePage = this.Page as IPersonalPage;
if (currentMySitePage != null && !currentMySitePage.IsProfileError)
{
SPSite personalSite = currentMySitePage.PersonalSite; // Will not leak.
// ...
}
Dim currentMySitePage As IPersonalPage = TryCast(Me.Page, IPersonalPage)
If currentMySitePage IsNot Nothing AndAlso (Not currentMySitePage.IsProfileError) Then
Dim personalSite As SPSite = currentMySitePage.PersonalSite ' Will not leak.
' ...
End If
Les objets SPWeb
Cette section décrit les situations dans lesquelles les objets SPWeb sont renvoyés et doivent éventuellement être supprimés.
La propriété SPWeb.ParentWeb
Conseils mis à jour
Les conseils précédents recommandaient la suppression des SPWeb.ParentWeb par l’application appelante. Les conseils officiels ont changé. Le nettoyage de la suppression est automatiquement géré par SharePoint Foundation et SharePoint Server.
Notes
Cette méthode conseillée résout le problème identifié par l’Outil de vérification de suppression SharePoint, tel que SPDisposeCheckID_170.
Bonne pratique de programmation
using (SPSite site = new SPSite("https://localhost"))
{
using (SPWeb web = site.OpenWeb())
{
SPList list = web.Lists["Announcements"];
SPWeb parentWeb = list.ParentWeb; //No explicit dispose required.
}
}
Using site As New SPSite("https://localhost")
Using web As SPWeb = site.OpenWeb()
Dim list As SPList = web.Lists("Announcements")
Dim parentWeb As SPWeb = list.ParentWeb 'No explicit dispose required.
End Using
End Using
La propriété SPWeb.Webs
Cette section décrit les méthodes, les propriétés ou les opérateurs dans la collection de propriétés Webs qui requièrent la suppression de l’objet SPWeb après l’accès.
La propriété SPWeb.Webs
La propriété SPWeb.Webs renvoie un objet SPWebCollection. Les objets SPWeb dans cette collection doivent être supprimés.
Notes
Cette méthode conseillée résout le problème identifié par l’Outil de vérification de suppression SharePoint (éventuellement en anglais) tel que SPDisposeCheckID_180.
Mauvaise pratique de programmation
void WebsLeak()
{
using (SPSite siteCollection = new SPSite("http://moss"))
{
using (SPWeb outerWeb = siteCollection.OpenWeb())
{
foreach (SPWeb innerWeb in outerWeb.Webs)
{
// SPWeb innerWeb leak.
}
} // SPWeb object outerWeb.Dispose() automatically called.
} // SPSite object siteCollection.Dispose() automatically called.
}
Private Sub WebsLeak()
Using siteCollection As New SPSite("http://moss")
Using outerWeb As SPWeb = siteCollection.OpenWeb()
For Each innerWeb As SPWeb In outerWeb.Webs
' SPWeb innerWeb leak.
Next
End Using ' SPWeb object outerWeb.Dispose() automatically called.
End Using ' SPSite object siteCollection.Dispose() automatically called.
End Sub
Bonne pratique de programmation
void WebsNoLeak()
{
using (SPSite siteCollection = new SPSite("http://moss"))
{
using (SPWeb outerWeb = siteCollection.OpenWeb())
{
foreach (SPWeb innerWeb in outerWeb.Webs)
{
try // Should be first statement after foreach.
{
// ...
}
finally
{
if(innerWeb != null)
innerWeb.Dispose();
}
}
} // SPWeb object outerWeb.Dispose() automatically called.
} // SPSite object siteCollection.Dispose() automatically called.
}
Private Sub WebsNoLeak()
Using siteCollection As New SPSite("http://moss")
Using outerWeb As SPWeb = siteCollection.OpenWeb()
For Each innerWeb As SPWeb In outerWeb.Webs
Try ' Should be first statement after foreach.
' ...
Finally
If innerWeb IsNot Nothing Then
innerWeb.Dispose()
End If
End Try
Next
End Using ' SPWeb object outerWeb.Dispose() automatically called.
End Using ' SPSite object siteCollection.Dispose() automatically called.
End Sub
La méthode SPWeb.Webs.Add
La méthode SPWeb.Webs.Add (ou SPWebCollection.Add) crée et renvoie un nouvel objet SPWeb. Vous devez supprimer tout objet SPWeb renvoyé via cette méthode d’appel.
Notes
Cette méthode conseillée résout le problème identifié par l’Outil de vérification de suppression SharePoint tel que SPDisposeCheckID_190.
Mauvaise pratique de programmation
void WebsAddLeak(string strWebUrl)
{
using (SPSite siteCollection = new SPSite("http://moss"))
{
using (SPWeb web = siteCollection.OpenWeb())
{
SPWeb addedWeb = web.Webs.Add(strWebUrl); // Will leak.
} // SPWeb object web.Dispose() automatically called.
} // SPSite object siteCollection.Dispose() automatically called.
}
Private Sub WebsAddLeak(ByVal strWebUrl As String)
Using siteCollection As New SPSite("http://moss")
Using web As SPWeb = siteCollection.OpenWeb()
Dim addedWeb As SPWeb = web.Webs.Add(strWebUrl) ' Will leak.
End Using ' SPWeb object web.Dispose() automatically called.
End Using ' SPSite object siteCollection.Dispose() automatically called.
End Sub
Bonne pratique de programmation
void WebsAddNoLeak(string strWebUrl)
{
using (SPSite siteCollection = new SPSite("http://moss"))
{
using (SPWeb web = siteCollection.OpenWeb())
{
using (SPWeb addedWeb = web.Webs.Add(strWebUrl))
{
//..
}
} // SPWeb object web.Dispose() automatically called.
} // SPSite object siteCollection.Dispose() automatically called.
}
Private Sub WebsAddNoLeak(ByVal strWebUrl As String)
Using siteCollection As New SPSite("http://moss")
Using web As SPWeb = siteCollection.OpenWeb()
Using addedWeb As SPWeb = web.Webs.Add(strWebUrl)
'..
End Using
End Using ' SPWeb object web.Dispose() automatically called.
End Using ' SPSite object siteCollection.Dispose() automatically called.
End Sub
L’opérateur index SPWeb.Webs[]
L’opérateur index SPWeb.Webs[] renvoie un nouvel objet SPWeb pour chaque accès. Un objet SPWeb est créé en appelant la méthode OpenWeb, même si cet objet a déjà été utilisé. Les exemples de code suivants entraînent une conservation à long terme de ces objets dans la mémoire utilisée par le .NET Framework.
Mauvaise pratique de programmation n° 1
Utilisation de la boucle For
int i;
SPWeb oSPWeb, oSPWeb2;
SPSite oSPSite = SPControl.GetContextSite(Context);
oSPWeb = oSPSite.OpenWeb();
for(i = 0;i < oSPWeb.Webs.Count;i++)
{
oSPWeb2 = oSPWeb.Webs[i];
BuildTableRow(oDisplayTable, "Web", oSPWeb2.Title);
}
Dim i As Integer
Dim oSPWeb, oSPWeb2 As SPWeb
Dim oSPSite As SPSite = SPControl.GetContextSite(Context)
oSPWeb = oSPSite.OpenWeb()
For i = 0 To oSPWeb.Webs.Count - 1
oSPWeb2 = oSPWeb.Webs(i)
BuildTableRow(oDisplayTable, "Web", oSPWeb2.Title)
Next i
Mauvaise pratique de programmation n° 2
Utilisation de la boucle foreach
SPWeb oSPWeb, oSPWeb2;
SPSite oSPSite = SPControl.GetContextSite(Context);
oSPWeb = oSPSite.OpenWeb();
foreach(SPWeb oSPWeb2 in oSPWebe.Webs)
{
BuildTableRow(oDisplayTable, "Web", oSPWeb2.Title);
}
Dim oSPWeb, oSPWeb2 As SPWeb
Dim oSPSite As SPSite = SPControl.GetContextSite(Context)
oSPWeb = oSPSite.OpenWeb()
For Each oSPWeb2 As SPWeb In oSPWebe.Webs
BuildTableRow(oDisplayTable, "Web", oSPWeb2.Title)
Next
La solution recommandée est la suppression à la fin de chaque boucle.
Bonne pratique de programmation n° 1
Utilisation de la boucle For
int i;
SPWeb oSPWeb, oSPWeb2;
SPSite oSPSite = SPControl.GetContextSite(Context);
oSPWeb = oSPSite.OpenWeb();
for(i = 0;i < oSPWeb.Webs.Count;i++)
{
oSPWeb2 = oSPWeb.Webs[i];
BuildTableRow(oDisplayTable, "Web", oSPWeb2.Title);
oSPWeb2.Dispose();
}
oSPWeb.Dispose();
Dim i As Integer
Dim oSPWeb, oSPWeb2 As SPWeb
Dim oSPSite As SPSite = SPControl.GetContextSite(Context)
oSPWeb = oSPSite.OpenWeb()
For i = 0 To oSPWeb.Webs.Count - 1
oSPWeb2 = oSPWeb.Webs(i)
BuildTableRow(oDisplayTable, "Web", oSPWeb2.Title)
oSPWeb2.Dispose()
Next i
oSPWeb.Dispose()
Bonne pratique de programmation n° 2
Utilisation de la boucle foreach
SPWeb oSPWeb, oSPWeb2;
SPSite oSPSite = SPControl.GetContextSite(Context);
oSPWeb = oSPSite.OpenWeb();
foreach(SPWeb oSPWeb2 in oSPWeb.Webs)
{
BuildTableRow(oDisplayTable, "Web", oSPWeb2.Title);
oSPWeb2.Dispose();
}
oSPWeb.Dispose();
Dim oSPWeb, oSPWeb2 As SPWeb
Dim oSPSite As SPSite = SPControl.GetContextSite(Context)
oSPWeb = oSPSite.OpenWeb()
For Each oSPWeb2 As SPWeb In oSPWeb.Webs
BuildTableRow(oDisplayTable, "Web", oSPWeb2.Title)
oSPWeb2.Dispose()
Next
oSPWeb.Dispose()
Bonne pratique de programmation n° 3
Utilisation de la boucle for avec suppression automatique
int i;
SPWeb oSPWeb, oSPWeb2;
SPSite oSPSite = SPControl.GetContextSite(Context);
using(oSPWeb = oSPSite.OpenWeb())
{
for(i = 0;i < oSPWeb.Webs.Count;i++)
{
Using(oSPWeb2 = oSPWeb.Webs[i])
{
BuildTableRow(oDisplayTable, "Web", oSPWeb2.Title);
}
}
}
Dim i As Integer
Dim oSPSite As SPSite = SPControl.GetContextSite(Context)
Using oSPWeb As SPWeb = oSPSite.OpenWeb()
For i = 0 To oSPWeb.Webs.Count - 1
Using oSPWeb2 As SPWeb = oSPWeb.Webs(i)
BuildTableRow(oDisplayTable, "Web", oSPWeb2.Title)
End Using
Next
End Using
Autres objets devant être supprimés
Cette section décrit quand appeler la méthode Dispose sur d’autres objets SharePoint.
La propriété Microsoft.SharePoint.Portal.SiteData.Area.Web
La propriété Web de la classe SharePoint.Portal.SiteData.Area renvoie un nouvel objet SPWeb à chaque accès. Toute utilisation de la propriété Area.Web doit s’accompagner d’un appel correspondant à la méthode Dispose. Même si les classes Area et AreaManager sont désormais obsolètes, le problème demeure lors de la migration du code hérité.
Notes
Cette méthode conseillée résout le problème identifié par l’Outil de vérification de suppression SharePoint tel que SPDisposeCheckID_500.
Mauvaise pratique de programmation
void AreaWebLeak()
{
// AreaManager and Area are obsolete in SharePoint Server, but this
// should still be noted.
Area area = AreaManager.GetArea(PortalContext.Current, new Guid("{GUID}"));
string str = area.Web.Title;
// SPWeb area.Web leak.
}
Private Sub AreaWebLeak()
' AreaManager and Area are obsolete in SharePoint Server, but this
' should still be noted.
Dim area As Area = AreaManager.GetArea(PortalContext.Current, New Guid("{GUID}"))
Dim str As String = area.Web.Title
' SPWeb area.Web leak.
End Sub
Bonne pratique de programmation
public void AreaWebNoLeak()
{
// AreaManager and Area are obsolete but this should still be noted.
Area area = AreaManager.GetArea(PortalContext.Current, new Guid("{GUID}"));
using (SPWeb areaWeb = area.Web)
{
string str = areaWeb.Title;
}
}
Public Sub AreaWebNoLeak()
' AreaManager and Area are obsolete but this should still be noted.
Dim area As Area = AreaManager.GetArea(PortalContext.Current, New Guid("{GUID}"))
Using areaWeb As SPWeb = area.Web
Dim str As String = areaWeb.Title
End Using
End Sub
Les méthodes SPControl.GetContextSite et SPControl.GetContextWeb
Si l’objet est obtenu à partir des objets de contexte SharePoint (les méthodes GetContextSite et GetContextWeb de la classe SPControl), l’application appelante ne doit pas appeler la méthode Dispose sur l’objet. Cela pourrait entraîner un comportement imprévisible ou l’échec du modèle d’objet SharePoint. Cela est dû à une liste interne qui est conservée dans les objets SPSite et SPWeb dérivés de cette manière. En interne, le modèle objet dresse cette liste une fois l’exécution de la page terminée afin de correctement supprimer les objets.
Vous devez toujours supprimer un objet créé à partir de ces objets, par exemple, si un site Web est ouvert à partir d’un objet SPSite obtenu à l’aide de la méthode GetContextSite.
Notes
Cette méthode conseillée résout le problème identifié par l’Outil de vérification de suppression SharePoint tel que SPDisposeCheckID_210.
Mauvaise pratique de programmation
void SPControlBADPractice()
{
SPSite siteCollection = SPControl.GetContextSite(Context);
siteCollection.Dispose(); // DO NOT DO THIS.
SPWeb web = SPControl.GetContextWeb(Context);
web.Dispose(); // DO NOT DO THIS.
}
Private Sub SPControlBADPractice()
Dim siteCollection As SPSite = SPControl.GetContextSite(Context)
siteCollection.Dispose() ' DO NOT DO THIS.
Dim web As SPWeb = SPControl.GetContextWeb(Context)
web.Dispose() ' DO NOT DO THIS.
End Sub
Bonne pratique de programmation
void SPControlBestPractice()
{
SPSite siteCollection = SPControl.GetContextSite(Context);
SPWeb web = SPControl.GetContextWeb(Context);
// Do NOT call Dispose().
}
Private Sub SPControlBestPractice()
Dim siteCollection As SPSite = SPControl.GetContextSite(Context)
Dim web As SPWeb = SPControl.GetContextWeb(Context)
' Do NOT call Dispose().
End Sub
Microsoft.SharePoint.WebPartPages.SPLimitedWebPartManager
La classe SPLimitedWebPartManager contient une référence à un objet SPWeb interne qui doit être supprimé.
Notes
Cette méthode conseillée résout le problème identifié par l’Outil de vérification de suppression SharePoint tel que SPDisposeCheckID_160.
Mauvaise pratique de programmation
void SPLimitedWebPartManagerLeak()
{
using (SPSite siteCollection = new SPSite("http://moss"))
{
using (SPWeb web = siteCollection.OpenWeb())
{
SPFile page = web.GetFile("Source_Folder_Name/Source_Page");
SPLimitedWebPartManager webPartManager =
page.GetLimitedWebPartManager(PersonalizationScope.Shared);
// SPWeb object webPartManager.Web leaked.
} // SPWeb object web.Dispose() automatically called.
} // SPSite object siteCollection.Dispose() automatically called.
}
Private Sub SPLimitedWebPartManagerLeak()
Using siteCollection As New SPSite("http://moss")
Using web As SPWeb = siteCollection.OpenWeb()
Dim page As SPFile = web.GetFile("Source_Folder_Name/Source_Page")
Dim webPartManager As SPLimitedWebPartManager = page.GetLimitedWebPartManager(PersonalizationScope.Shared)
' SPWeb object webPartManager.Web leaked.
End Using ' SPWeb object web.Dispose() automatically called.
End Using ' SPSite object siteCollection.Dispose() automatically called.
End Sub
Bonne pratique de programmation
void SPLimitedWebPartManagerLeak()
{
using (SPSite siteCollection = new SPSite("http://moss"))
{
using (SPWeb web = siteCollection.OpenWeb())
{
SPFile page = web.GetFile("Source_Folder_Name/Source_Page");
SPLimitedWebPartManager webPartManager =
page.GetLimitedWebPartManager(PersonalizationScope.Shared);
webPartManaber.Web.Dispose();
} // SPWeb object web.Dispose() automatically called.
} // SPSite object siteCollection.Dispose() automatically called.
}
Private Sub SPLimitedWebPartManagerLeak()
Using siteCollection As New SPSite("http://moss")
Using web As SPWeb = siteCollection.OpenWeb()
Dim page As SPFile = web.GetFile("Source_Folder_Name/Source_Page")
Dim webPartManager As SPLimitedWebPartManager = page.GetLimitedWebPartManager(PersonalizationScope.Shared)
webPartManaber.Web.Dispose()
End Using ' SPWeb object web.Dispose() automatically called.
End Using ' SPSite object siteCollection.Dispose() automatically called.
End Sub
Microsoft.SharePoint.Publishing.PublishingWeb
Notes
L’espace de noms Microsoft.SharePoint.Publishing appartient à SharePoint Server 2010. Cette section s’applique à SharePoint Server 2010 et non à SharePoint Foundation 2010.
La méthode GetPublishingWebs de la classe PublishingWeb renvoie un objet PublishingWebCollection. Vous devez appeler la méthode Close sur chaque objet innerPubWeb répertorié. Lorsque vous appelez uniquement la méthode GetPublishingWeb, il n’est pas nécessaire d’appeler Close.
Notes
Cette méthode conseillée résout le problème identifié par l’Outil de vérification de suppression SharePoint tel que SPDisposeCheckID_300.
Mauvaise pratique de programmation
void PublishingWebCollectionLeak()
{
using (SPSite siteCollection = new SPSite("http://moss"))
{
using (SPWeb web = siteCollection.OpenWeb())
{
// Passing in SPWeb object that you own, no dispose needed on
// outerPubWeb.
PublishingWeb outerPubWeb = PublishingWeb.GetPublishingWeb(web);
PublishingWebCollection pubWebCollection = outerPubWeb.GetPublishingWebs();
foreach (PublishingWeb innerPubWeb in pubWebCollection)
{
// innerPubWeb leak.
}
// PublishingWeb will leak for each innerPubWeb referenced
} // SPWeb object web.Dispose() automatically called.
} // SPSite object siteCollection.Dispose() automatically called.
}
Private Sub PublishingWebCollectionLeak()
Using siteCollection As New SPSite("http://moss")
Using web As SPWeb = siteCollection.OpenWeb()
' Passing in SPWeb object that you own, no dispose needed on
' outerPubWeb.
Dim outerPubWeb As PublishingWeb = PublishingWeb.GetPublishingWeb(web)
Dim pubWebCollection As PublishingWebCollection = outerPubWeb.GetPublishingWebs()
For Each innerPubWeb As PublishingWeb In pubWebCollection
' innerPubWeb leak.
Next
' PublishingWeb will leak for each innerPubWeb referenced
End Using ' SPWeb object web.Dispose() automatically called.
End Using ' SPSite object siteCollection.Dispose() automatically called.
End Sub
Bonne pratique de programmation
void PublishingWebCollectionNoLeak()
{
using (SPSite siteCollection = new SPSite("http://moss"))
{
using (SPWeb web = siteCollection.OpenWeb())
{
// Passing in SPWeb object that you own, no dispose needed on
// outerPubWeb.
PublishingWeb outerPubWeb = PublishingWeb.GetPublishingWeb(web);
PublishingWebCollection pubWebCollection = outerPubWeb.GetPublishingWebs();
foreach (PublishingWeb innerPubWeb in pubWebCollection)
{
try
{
// ...
}
finally
{
if(innerPubWeb != null)
innerPubWeb.Close();
}
}
} // SPWeb object web.Dispose() automatically called.
} // SPSite object siteCollection.Dispose() automatically called.
}
Private Sub PublishingWebCollectionNoLeak()
Using siteCollection As New SPSite("http://moss")
Using web As SPWeb = siteCollection.OpenWeb()
' Passing in SPWeb object that you own, no dispose needed on
' outerPubWeb.
Dim outerPubWeb As PublishingWeb = PublishingWeb.GetPublishingWeb(web)
Dim pubWebCollection As PublishingWebCollection = outerPubWeb.GetPublishingWebs()
For Each innerPubWeb As PublishingWeb In pubWebCollection
Try
' ...
Finally
If innerPubWeb IsNot Nothing Then
innerPubWeb.Close()
End If
End Try
Next
End Using ' SPWeb object web.Dispose() automatically called.
End Using ' SPSite object siteCollection.Dispose() automatically called.
End Sub
Notes
Il existe une exigence similaire pour appeler Close sur chaque objet PublishingWeb créé en appelant la méthode Add sur la collection PublishingWebCollection renvoyée par Microsoft.SharePoint.Publishing.PublishingWeb.GetPublishingWebs. Pour obtenir un exemple de code, voir la méthode GetPublishingWebs(). Cette méthode conseillée résout le problème identifié par l’Outil de vérification de suppression SharePoint tel que SPDisposeCheckID_310.
La méthode Microsoft.SharePoint.Publishing.PublishingWeb.GetVariation renvoie un objet PublishingWeb qui doit être supprimé.
Notes
Cette méthode conseillée résout le problème identifié par l’Outil de vérification de suppression SharePoint tel que SPDisposeCheckID_320.
Mauvaise pratique de programmation
void GetVariationLeak()
{
using (SPSite siteCollection = new SPSite("http://moss"))
{
using (SPWeb web = siteCollection.OpenWeb())
{
PublishingWeb publishingWeb = PublishingWeb.GetPublishingWeb(web); // Passing in SPWeb object, so no Close() needed
VariationLabel variationLabel = Variations.Current.UserAccessibleLabels[0];
PublishingWeb variationPublishingWeb = publishingWeb.GetVariation(variationLabel); // Must be Closed().
// ...
} // SPWeb object outerWeb.Dispose() automatically called.
} // SPSite object siteCollection.Dispose() automatically called.
}
Private Sub GetVariationLeak()
Using siteCollection As New SPSite("http://moss")
Using web As SPWeb = siteCollection.OpenWeb()
Dim publishingWeb As PublishingWeb = PublishingWeb.GetPublishingWeb(web) ' Passing in SPWeb object, so no Close() needed
Dim variationLabel As VariationLabel = Variations.Current.UserAccessibleLabels(0)
Dim variationPublishingWeb As PublishingWeb = publishingWeb.GetVariation(variationLabel) ' Must be Closed().
' ...
End Using ' SPWeb object outerWeb.Dispose() automatically called.
End Using ' SPSite object siteCollection.Dispose() automatically called.
End Sub
Bonne pratique de programmation
void GetVariationNoLeak()
{
using (SPSite siteCollection = new SPSite("http://moss"))
{
using (SPWeb web = siteCollection.OpenWeb())
{
PublishingWeb variationPublishingWeb = null;
try
{
PublishingWeb publishingWeb = PublishingWeb.GetPublishingWeb(web); // Passing in SPWeb object, so no Close() needed.
VariationLabel variationLabel = Variations.Current.UserAccessibleLabels[0];
variationPublishingWeb = publishingWeb.GetVariation(variationLabel); // Must be Closed().
// ...
}
finally
{
if(variationPublishingWeb != null)
variationPublishingWeb.Close();
}
} // SPWeb object web.Dispose() automatically called.
} // SPSite object siteCollection.Dispose() automatically called.
}
Private Sub GetVariationNoLeak()
Using siteCollection As New SPSite("http://moss")
Using web As SPWeb = siteCollection.OpenWeb()
Dim variationPublishingWeb As PublishingWeb = Nothing
Try
Dim publishingWeb As PublishingWeb = PublishingWeb.GetPublishingWeb(web) ' Passing in SPWeb object, so no Close() needed.
Dim variationLabel As VariationLabel = Variations.Current.UserAccessibleLabels(0)
variationPublishingWeb = publishingWeb.GetVariation(variationLabel) ' Must be Closed().
' ...
Finally
If variationPublishingWeb IsNot Nothing Then
variationPublishingWeb.Close()
End If
End Try
End Using ' SPWeb object web.Dispose() automatically called.
End Using ' SPSite object siteCollection.Dispose() automatically called.
End Sub
Les modèles de suppression par méthode croisée
L’exemple suivant illustre la pratique courante consistant à appliquer aux objets SPSite et SPWeb des méthodes croisées dans une classe. Ce modèle de conception est parfois requis, mais assurez-vous de ne pas négliger l’heure d’appel appropriée Dispose lorsque vous avez terminé avec les appels de méthode croisée. L’exemple de code suivant illustre un modèle où SPSite et SPWeb subissent une fuite lorsque la classe passe hors de portée.
public class CrossMethodLeak
{
private SPSite _siteCollection = null;
private SPWeb _web = null;
public void MethodA()
{
_siteCollection = new SPSite("http://moss");
_web = _siteCollection.OpenWeb();
}
public void MethodB()
{
if (_web != null)
{
string title = _web.Title;
}
}
public void MethodC()
{
if (_web != null)
{
string name = _web.Name;
}
}
}
Public Class CrossMethodLeak
Private _siteCollection As SPSite = Nothing
Private _web As SPWeb = Nothing
Public Sub MethodA()
_siteCollection = New SPSite("http://moss")
_web = _siteCollection.OpenWeb()
End Sub
Public Sub MethodB()
If _web IsNot Nothing Then
Dim title As String = _web.Title
End If
End Sub
Public Sub MethodC()
If _web IsNot Nothing Then
Dim name As String = _web.Name
End If
End Sub
End Class
Conclusion
Étant donné que plusieurs objets SharePoint implémentent l’interface IDisposable, vous devez être prudent lors de l’utilisation de ces objets afin d’éviter de les conserver en mémoire. En suivant les instructions de suppression des objets SharePoint, tel que décrit dans cet article, vous pouvez contribuer à garantir la fiabilité de votre code personnalisé.
Remerciements
Nous tenons à remercier les personnes suivantes pour leur contribution et leurs conseils dans le cadre de la rédaction de cet article :
Steve Sheppard, Microsoft Corporation
Chris Gideon, Microsoft Corporation
Rashid Aga, Microsoft Corporation
Voir aussi
Autres ressources
Outil de vérification de suppression SharePoint (éventuellement en anglais)
Modèles et pratiques SharePoint (éventuellement en anglais)
Centre pour développeurs Windows SharePoint Services
Centre pour développeurs SharePoint Server 2007
Meilleures pratiques en matière de personnalisation des produits et technologies SharePoint
Blog pour les développeurs SharePoint de Roger Lamb (éventuellement en anglais)
Meilleures pratiques : Problèmes de codage courants rencontrés avec le modèle d’objet SharePoint