SharePoint 2007 : SPDisposeCheck ne vérifierait pas tout les patterns de dispose connus

[via Stephen Vick’s Blog ]

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) :

  • CreatingSPSiteLeak
  • AllWebsForEachLeak
  • AllWebsIndexerLeak
  • SPLimitedWebPartManagerLeak
  • WebsLeak
  • PublishingWebCollectionLeak
  • GetVariationLeak
  • PersonalSiteLeak
  • SPSiteCollectionIndexerLeak
  • SPSiteCollectionForEachLeak
  • CrossMethodLeak.MethodB
  • CrossMethodLeak.MethodC
Ce qui fait quand même une petite tripoté de méthodes et d'objets qui ne sont pas vérifiés.

Voilà le fichier en question :

   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.

EDIT :Selon Paul Andrew, Il semblerait que toutes les erreurs soient détectées si vous compilez votre code en release. Une future release est à prévoir qui corrigerait toute ses erreurs.

<Philippe/>

Publié vendredi 20 mars 2009 10:43 par phil
Classé sous , , ,
Ce post vous a plu ? Ajoutez le dans vos favoris pour ne pas perdre de temps à le retrouver le jour où vous en aurez besoin :

Commentaires

About phil

Philippe Sentenac est Consultant SharePoint à Wygwam en région Parisienne. Il intervient essentiellement sur des missions liées à SharePoint (2007 et 2010 ) mais aussi autour du Web 2.0. Plus généralement, il s'intéresse à l'ASP.Net (MVC) , à Silverlight, et à tout ce qui est orienté Web en rapport avec les nouvelles technologies, qu'il pratique depuis 2006. Féru de développement, il est passionné par les problématiques de méthodologies et d'industrialisation du développement.

Les 10 derniers blogs postés

- Merci par Blog de Jérémy Jeanson le 10-01-2019, 20:47

- Office 365: Script PowerShell pour auditer l’usage des Office Groups de votre tenant par Blog Technique de Romelard Fabrice le 04-26-2019, 11:02

- Office 365: Script PowerShell pour auditer l’usage de Microsoft Teams de votre tenant par Blog Technique de Romelard Fabrice le 04-26-2019, 10:39

- Office 365: Script PowerShell pour auditer l’usage de OneDrive for Business de votre tenant par Blog Technique de Romelard Fabrice le 04-25-2019, 15:13

- Office 365: Script PowerShell pour auditer l’usage de SharePoint Online de votre tenant par Blog Technique de Romelard Fabrice le 02-27-2019, 13:39

- Office 365: Script PowerShell pour auditer l’usage d’Exchange Online de votre tenant par Blog Technique de Romelard Fabrice le 02-25-2019, 15:07

- Office 365: Script PowerShell pour auditer le contenu de son Office 365 Stream Portal par Blog Technique de Romelard Fabrice le 02-21-2019, 17:56

- Office 365: Script PowerShell pour auditer le contenu de son Office 365 Video Portal par Blog Technique de Romelard Fabrice le 02-18-2019, 18:56

- Office 365: Script PowerShell pour extraire les Audit Log basés sur des filtres fournis par Blog Technique de Romelard Fabrice le 01-28-2019, 16:13

- SharePoint Online: Script PowerShell pour désactiver l’Option IRM des sites SPO non autorisés par Blog Technique de Romelard Fabrice le 12-14-2018, 13:01