Dans la série des nouvelles qui ne font pas vraiment plaisir, il semblerait que SPDisposeCheck ne vérifie pas tout les patterns de Dispose présentés dans les liens suivants :
En effet, Stephen Vick montre que SPDisposeCheck ne vérifie pas les méthodes suivantes dans le fichier utilisé (basé sur le post de Roger Lamb) :
Ce qui fait quand même une petite tripoté de méthodes et d'objets qui ne sont pas vérifiés.
1: namespace SPDisposeTest
2: { 3: public class Class1
4: { 5: void CreatingSPSiteLeak()
6: { 7: SPSite siteCollection = new SPSite("http://moss"); 8: // siteCollection leaked
9: }
10:
11: void CreatingSPSiteExplicitDisposeNoLeak()
12: { 13: SPSite siteCollection = null;
14: try
15: { 16: siteCollection = new SPSite("http://moss"); 17: }
18: finally
19: { 20: if (siteCollection != null)
21: siteCollection.Dispose();
22: }
23: }
24:
25: void CreatingSPSiteWithAutomaticDisposeNoLeak()
26: { 27: using (SPSite siteCollection = new SPSite("http://moss")) 28: { 29: } // SPSite object siteCollection.Dispose() automatically called
30: }
31:
32: void OpenWebLeak()
33: { 34: using (SPWeb web = new SPSite(SPContext.Current.Web.Url).OpenWeb())
35: { 36: // SPSite leaked !
37: } // SPWeb object web.Dispose() automatically called
38: }
39:
40: void OpenWebNoLeak()
41: { 42: using (SPSite siteCollection = new SPSite("http://moss")) 43: { 44: using (SPWeb web = siteCollection.OpenWeb())
45: { 46: } // SPWeb object web.Dispose() automatically called
47: } // SPSite object siteCollection.Dispose() automatically called
48: }
49:
50: void AllWebsForEachLeak()
51: { 52: using (SPSite siteCollection = new SPSite("http://moss")) 53: { 54: using (SPWeb outerWeb = siteCollection.OpenWeb())
55: { 56: foreach (SPWeb innerWeb in siteCollection.AllWebs)
57: { 58: // explicit dispose here to avoid OOM’s with large # of webs
59: }
60: } // SPWeb object outerWeb.Dispose() automatically called
61: } // SPSite object siteCollection.Dispose() automatically called
62: }
63:
64: void AllWebsForEachNoLeakOrMemoryOOM()
65: { 66: using (SPSite siteCollection = new SPSite("http://moss")) 67: { 68: using (SPWeb outerWeb = siteCollection.OpenWeb())
69: { 70: foreach (SPWeb innerWeb in siteCollection.AllWebs)
71: { 72: try
73: { 74: // …
75: }
76: finally
77: { 78: if (innerWeb != null)
79: innerWeb.Dispose();
80: }
81: }
82: } // SPWeb object outerWeb.Dispose() automatically called
83: } // SPSite object siteCollection.Dispose() automatically called
84: }
85:
86: void AllWebsIndexerLeak()
87: { 88: using (SPSite siteCollection = new SPSite("http://moss")) 89: { 90: SPWeb web = siteCollection.AllWebs[0];
91: // SPWeb web leaked
92: } // SPSite object siteCollection.Dispose() automatically called
93: }
94:
95: void AllWebsIndexerNoLeak()
96: { 97: using (SPSite siteCollection = new SPSite("http://moss")) 98: { 99: using (SPWeb web = siteCollection.AllWebs[0])
100: { 101: } // SPWeb object web.Dispose() automatically called
102: } // SPSite object siteCollection.Dispose() automatically called
103: }
104:
105: void AllWebsAddLeak()
106: { 107: using (SPSite siteCollection = new SPSite("http://moss")) 108: { 109: SPWeb web = siteCollection.AllWebs.Add("site-relative URL"); 110: // SPWeb web Leaked
111: } // SPSite object siteCollection.Dispose() automatically called
112: }
113:
114: void AllWebsAddNoLeak()
115: { 116: using (SPSite siteCollection = new SPSite("http://moss")) 117: { 118: using (SPWeb web = siteCollection.AllWebs.Add("site-relative URL")) 119: { 120: } // SPWeb object web.Dispose() automatically called
121: } // SPSite object siteCollection.Dispose() automatically called
122: }
123:
124: void SPLimitedWebPartManagerLeak()
125: { 126: using (SPSite siteCollection = new SPSite("http://moss")) 127: { 128: using (SPWeb web = siteCollection.OpenWeb())
129: { 130: SPFile page = web.GetFile("Source_Folder_Name/Source_Page"); 131: SPLimitedWebPartManager webPartManager = page.GetLimitedWebPartManager(PersonalizationScope.Shared);
132: // SPWeb object webPartManager.Web leaked
133: } // SPWeb object web.Dispose() automatically called
134: } // SPSite object siteCollection.Dispose() automatically called
135: }
136:
137: void SPLimitedWebPartManagerNoLeak()
138: { 139: using (SPSite siteCollection = new SPSite("http://moss")) 140: { 141: using (SPWeb web = siteCollection.OpenWeb())
142: { 143: SPFile page = web.GetFile("Source_Folder_Name/Source_Page"); 144: using (SPLimitedWebPartManager webPartManager = page.GetLimitedWebPartManager(PersonalizationScope.Shared))
145: { 146: try
147: { 148: // …
149: }
150: finally
151: { 152: webPartManager.Web.Dispose();
153: }
154: }
155: } // SPWeb object web.Dispose() automatically called
156: } // SPSite object siteCollection.Dispose() automatically called
157: }
158:
159: void WebsLeak()
160: { 161: using (SPSite siteCollection = new SPSite("http://moss")) 162: { 163: using (SPWeb outerWeb = siteCollection.OpenWeb())
164: { 165: foreach (SPWeb innerWeb in outerWeb.Webs)
166: { 167: // SPWeb innerWeb leak
168: }
169: } // SPWeb object outerWeb.Dispose() automatically called
170: } // SPSite object siteCollection.Dispose() automatically called
171: }
172:
173: void WebsNoLeak()
174: { 175: using (SPSite siteCollection = new SPSite("http://moss")) 176: { 177: using (SPWeb outerWeb = siteCollection.OpenWeb())
178: { 179: foreach (SPWeb innerWeb in outerWeb.Webs)
180: { 181: try
182: //should be 1st statement after foreach
183: { 184: // …
185: }
186: finally
187: { 188: if (innerWeb != null)
189: innerWeb.Dispose();
190: }
191: }
192: } // SPWeb object outerWeb.Dispose() automatically called
193: } // SPSite object siteCollection.Dispose() automatically called
194: }
195:
196: void WebsAddLeak(string strWebUrl)
197: { 198: using (SPSite siteCollection = new SPSite("http://moss")) 199: { 200: using (SPWeb web = siteCollection.OpenWeb())
201: { 202: SPWeb addedWeb = web.Webs.Add(strWebUrl); // will leak
203: } // SPWeb object web.Dispose() automatically called
204: } // SPSite object siteCollection.Dispose() automatically called
205: }
206:
207: void WebsAddNoLeak(string strWebUrl)
208: { 209: using (SPSite siteCollection = new SPSite("http://moss")) 210: { 211: using (SPWeb web = siteCollection.OpenWeb())
212: { 213: using (SPWeb addedWeb = web.Webs.Add(strWebUrl))
214: { 215: //..
216: }
217: } // SPWeb object web.Dispose() automatically called
218: } // SPSite object siteCollection.Dispose() automatically called
219: }
220:
221: void SPWebCollectionAddLeak(string strWebUrl)
222: { 223: using (SPSite siteCollection = new SPSite("http://moss")) 224: { 225: using (SPWeb outerWeb = siteCollection.OpenWeb())
226: { 227: SPWebCollection webCollection = siteCollection.AllWebs; // no AllWebs leak just getting reference
228: SPWeb innerWeb = webCollection.Add(strWebUrl); // must dispose of innerWeb
229: // innerWeb Leak
230: } // SPWeb object outerWeb.Dispose() automatically called
231: } // SPSite object siteCollection.Dispose() automatically called
232: }
233:
234: void SPWebCollectionAddNoLeak(string strWebUrl)
235: { 236: using (SPSite siteCollection = new SPSite("http://moss")) 237: { 238: using (SPWeb outerWeb = siteCollection.OpenWeb())
239: { 240: SPWebCollection webCollection = siteCollection.AllWebs; // no AllWebs leak just getting reference
241: using (SPWeb innerWeb = webCollection.Add(strWebUrl))
242: { 243: //…
244: }
245: } // SPWeb object outerWeb.Dispose() automatically called
246: } // SPSite object siteCollection.Dispose() automatically called
247: }
248:
249: void SPControlBADPractice()
250: { 251: HttpContext Context = null;
252: SPSite siteCollection = SPControl.GetContextSite(Context);
253: siteCollection.Dispose(); // DO NOT DO THIS
254: SPWeb web = SPControl.GetContextWeb(Context);
255: web.Dispose(); // DO NOT DO THIS
256: }
257:
258: void SPControlBestPractice()
259: { 260: HttpContext Context = null;
261: SPSite siteCollection = SPControl.GetContextSite(Context);
262: SPWeb web = SPControl.GetContextWeb(Context);
263: // Do NOT call Dispose()
264: }
265:
266: void SPContextBADPractice()
267: { 268: SPSite siteCollection = SPContext.Current.Site;
269: siteCollection.Dispose(); // DO NOT DO THIS
270: SPWeb web = SPContext.Current.Web;
271: web.Dispose(); // DO NOT DO THIS
272: }
273:
274: void SPContextBestPractice()
275: { 276: SPSite siteCollection = SPContext.Current.Site;
277: SPWeb web = SPContext.Current.Web;
278: // Do NOT call Dispose()
279: }
280:
281: void PublishingWebCollectionLeak()
282: { 283: using (SPSite siteCollection = new SPSite("http://moss")) 284: { 285: using (SPWeb web = siteCollection.OpenWeb())
286: { 287: // passing in web you own, no dispose needed on outerPubWeb
288: PublishingWeb outerPubWeb = PublishingWeb.GetPublishingWeb(web);
289:
290: PublishingWebCollection pubWebCollection = outerPubWeb.GetPublishingWebs();
291: foreach (PublishingWeb innerPubWeb in pubWebCollection)
292: { 293: // innerPubWeb leak
294: }
295:
296: // PublishingWeb will leak for each innerPubWeb referenced
297: } // SPWeb object web.Dispose() automatically called
298: } // SPSite object siteCollection.Dispose() automatically called
299: }
300:
301: void PublishingWebCollectionNoLeak()
302: { 303: using (SPSite siteCollection = new SPSite("http://moss")) 304: { 305: using (SPWeb web = siteCollection.OpenWeb())
306: { 307: // passing in web you own, no dispose needed on outerPubWeb
308: PublishingWeb outerPubWeb = PublishingWeb.GetPublishingWeb(web);
309: PublishingWebCollection pubWebCollection = outerPubWeb.GetPublishingWebs();
310: foreach (PublishingWeb innerPubWeb in pubWebCollection)
311: { 312: try
313: { 314: // …
315: }
316: finally
317: { 318: if (innerPubWeb != null)
319: innerPubWeb.Close();
320: }
321: }
322: // outerPubWeb.Close(); not needed and if called will log warning in ULS log
323: } // SPWeb object web.Dispose() automatically called
324: } // SPSite object siteCollection.Dispose() automatically called
325: }
326:
327: void GetPublishingWebNoLeak()
328: { 329: using (SPSite siteCollection = new SPSite("http://moss")) 330: { 331: using (SPWeb web = siteCollection.OpenWeb())
332: { 333: // passing in web you own, no dispose needed on singlePubWeb
334: PublishingWeb singlePubWeb = PublishingWeb.GetPublishingWeb(web);
335: } // SPWeb object web.Dispose() automatically called
336: } // SPSite object siteCollection.Dispose() automatically called
337: }
338:
339: void GetVariationLeak()
340: { 341: using (SPSite siteCollection = new SPSite("http://moss")) 342: { 343: using (SPWeb web = siteCollection.OpenWeb())
344: { 345: PublishingWeb publishingWeb = PublishingWeb.GetPublishingWeb(web); // Passing in web so no Close() needed
346: VariationLabel variationLabel = Variations.Current.UserAccessibleLabels[0];
347: PublishingWeb variationPublishingWeb = publishingWeb.GetVariation(variationLabel); // must be Closed()
348: // …
349: } // SPWeb object web.Dispose() automatically called
350: } // SPSite object siteCollection.Dispose() automatically called
351: }
352:
353: void GetVariationNoLeak()
354: { 355: using (SPSite siteCollection = new SPSite("http://moss")) 356: { 357: using (SPWeb web = siteCollection.OpenWeb())
358: { 359: PublishingWeb variationPublishingWeb = null;
360: try
361: { 362: PublishingWeb publishingWeb = PublishingWeb.GetPublishingWeb(web); // Passing in web so no Close() needed
363: VariationLabel variationLabel = Variations.Current.UserAccessibleLabels[0];
364: variationPublishingWeb = publishingWeb.GetVariation(variationLabel); // must be Closed()
365: // …
366: }
367: finally
368: { 369: if (variationPublishingWeb != null)
370: variationPublishingWeb.Close();
371: }
372: } // SPWeb object outerWeb.Dispose() automatically called
373: } // SPSite object siteCollection.Dispose() automatically called
374: }
375:
376: void PersonalSiteLeak()
377: { 378: // open a site collection
379: using (SPSite siteCollection = new SPSite("http://moss")) 380: { 381: UserProfileManager profileManager = new UserProfileManager(ServerContext.GetContext(siteCollection));
382: UserProfile profile = profileManager.GetUserProfile("domain\\username"); 383: SPSite personalSite = profile.PersonalSite; // will leak
384: }
385: }
386:
387: void PersonalSiteNoLeak()
388: { 389: // open a site collection
390: using (SPSite siteCollection = new SPSite("http://moss")) 391: { 392: UserProfileManager profileManager = new UserProfileManager(ServerContext.GetContext(siteCollection));
393: UserProfile profile = profileManager.GetUserProfile("domain\\username"); 394: using (SPSite personalSite = profile.PersonalSite)
395: { 396:
397: // …
398: }
399: }
400: }
401:
402: void SPSiteCollectionIndexerLeak()
403: { 404: using (SPSite siteCollectionOuter = new SPSite("http://moss")) 405: { 406: SPWebApplication webApp = siteCollectionOuter.WebApplication;
407: SPSiteCollection siteCollections = webApp.Sites;
408:
409:
410: SPSite siteCollectionInner = siteCollections[0];
411: // SPSite siteCollectionInner leak
412: } // SPSite object siteCollectionOuter.Dispose() automatically called
413: }
414:
415: void SPSiteCollectionIndexerNoLeak()
416: { 417: using (SPSite siteCollectionOuter = new SPSite("http://moss")) 418: { 419: SPSite siteCollectionInner = null;
420: try
421: { 422: SPWebApplication webApp = siteCollectionOuter.WebApplication;
423: SPSiteCollection siteCollections = webApp.Sites;
424:
425:
426: siteCollectionInner = siteCollections[0];
427: }
428: finally
429: { 430: if (siteCollectionInner != null)
431: siteCollectionInner.Dispose();
432: }
433: } // SPSite object siteCollectionOuter.Dispose() automatically called
434: }
435:
436: void SPSiteCollectionForEachLeak()
437: { 438: using (SPSite siteCollectionOuter = new SPSite("http://moss")) 439: { 440: SPWebApplication webApp = siteCollectionOuter.WebApplication;
441: SPSiteCollection siteCollections = webApp.Sites;
442:
443: foreach (SPSite siteCollectionInner in siteCollections)
444: { 445: // SPSite siteCollectionInner leak
446: }
447: } // SPSite object siteCollectionOuter.Dispose() automatically called
448: }
449:
450: void SPSiteCollectionForEachNoLeak()
451: { 452: using (SPSite siteCollectionOuter = new SPSite("http://moss")) 453: { 454: SPWebApplication webApp = siteCollectionOuter.WebApplication;
455: SPSiteCollection siteCollections = webApp.Sites;
456:
457:
458: foreach (SPSite siteCollectionInner in siteCollections)
459: { 460: try
461: { 462: // …
463: }
464: finally
465: { 466: if (siteCollectionInner != null)
467: siteCollectionInner.Dispose();
468: }
469: }
470: } // SPSite object siteCollectionOuter.Dispose() automatically called
471: }
472:
473: void SPSiteCollectionAddLeak()
474: { 475: SPWebApplication webApp = new SPSite("http://moss").WebApplication; 476: SPSiteCollection siteCollections = webApp.Sites;
477: SPSite siteCollection = siteCollections.Add("sites/myNewSiteCollection", "DOMAIN\\User", "roger.lamb@litwareinc.com"); 478: // SPSite siteCollection leak
479: }
480:
481: void SPSiteCollectionAddNoLeak()
482: { 483: SPWebApplication webApp = new SPSite("http://moss").WebApplication; 484: SPSiteCollection siteCollections = webApp.Sites;
485: using (SPSite siteCollection = siteCollections.Add("sites/myNewSiteCollection", "DOMAIN\\User", "roger.lamb@litwareinc.com")) 486: { 487: } // SPSite object siteCollection.Dispose() automatically called
488: }
489:
490: public class CrossMethodLeak
491: { 492: private SPSite _siteCollection = null;
493: private SPWeb _web = null;
494:
495: public void MethodA()
496: { 497: _siteCollection = new SPSite("http://moss"); 498: _web = _siteCollection.OpenWeb();
499: }
500:
501: public void MethodB()
502: { 503: if (_web != null)
504: { 505: string title = _web.Title;
506: }
507: }
508:
509: public void MethodC()
510: { 511: if (_web != null)
512: { 513: string name = _web.Name;
514: }
515: }
516: }
517: }
518: }
Alors un conseil, en attendant que ce soit corrigé/confirmé, ne considérez pas SPDisposeCheck comme parole d'évangile.