When you develop SharePoint solution using code, you need to Dispose SPWeb appropriately to avoid memory Leaks. The general guideline for this are:
Dispose | Not to dispose |
OpenWeb()
AllWebs
site.AllWebs | RootWeb
SPWeb from SPContext
|
Ensure that you only dispose SPSite and SPWeb objects that your code owns.
Examples that you don’t own(Which means you should not use Dispose() to clear the memory reference of this objects)
- SPContext.Current.Web
- SPContext.Current.Site
- SPContext.Current.Site.RootWeb
Do not explicitly call Dispose() on the site.RootWeb property. The dispose cleanup will be handled automatically by the SharePoint and the .NET framework. For existing SharePoint customization removal of explicit RootWeb Dispose is recommended to avoid an edge case condition where the SPContext.Current.Web has equality to the SPSite.RootWeb. Problems can occur when disposing RootWeb when obtained from any variation of SPContext (For Example: SPContext.Site.RootWeb, SPContext.Current.Site.RootWeb and GetContextSite(Context).RootWeb ).
In general, there are three common cases where you do own the object(You can dispose these objects):
- When you new up your own SPSite object:
SPSite site = new SPSite(url); // site.Dispose();
- When you explicitly call SPSite.OpenWeb():
SPWeb web = site.OpenWeb(url); // web.Dispose();
- When you iterate through SPSite.AllWebs – this is an extremely expensive operation, so avoid if possible:
foreach(SPWeb web in site.AllWebs) {
// …
web.Dispose();
}
- Disposing the SPSite will close the associated SPWeb objects.
SPSite object is in effect.
public void RootWebBestPractice()
{
// Exception to "Best Practices: Using Disposable Windows SharePoint Services Objects" White paper
// Example 1 - 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
// Example 2 - SPContext and SPControl
SPWeb rootWeb2 = SPContext.Current.Site.RootWeb;
// Also would apply to SPControl.GetContextSite(Context);
// No explicit rootWeb2 dispose required because it's obtained from SPContext.Current.Site
}
This is very important. When you are basically just creating your own SPWeb objects you will need to make sure that you dispose of your objects correctly. The best way of doing this is encompassing your web object in a "Using" statement
using(SPSite site = new Site("http://sharepointdev/subsite");
{
// RootWeb would return the http://sharepointdev and OpenWeb() would return "subsite"
using(SPWeb web = site.OpenWeb())
{
// work with web object
} // web object disposed
} // site object disposed
Do NOT Dispose SPContext.Current.Web or SPSite.RootWeb
If you write a using statement such as:
// This is bad! m'kay ?
using(SPWeb web = SPContext.Current.Web)
{
}
What you are actually doing is disposing the SPContext.Current.Web object .. not just your own "web" object. THIS IS BAD. You should actually just declare them with a single, normal line, such as:
SPWeb web = SPContext.Current.Web;
And exactly the same applies to SPSite.RootWeb properties too!
Use of "using" Statement:
public static SPWeb ReturnSPWeb(string url) {
using (var site = new SPSite(url)) {
using (SPWeb web = site.OpenWeb()) {
return web;
}
}
}
When you return from within a using
block, the compiler will insert a Dispose on the used object before returning. Open your assembly in ildasm if you don’t believe me. So the above code is effectively equivalent to the following:
public static SPWeb ReturnSPWeb(string url) {
var site = new SPSite(url);
SPWeb web = site.OpenWeb();
web.Dispose();
site.Dispose();
return web;
}
There is a tool called SharePoint Dispose Checker which can help you to find potential memory leak.
To use SPDisposeChecker in you solution, you need to download the tool from MSDN Code Gallery and install it.After installing open the soution.
nice article....
ReplyDelete