Using Disposable Windows SharePoint Services Objects
We can employ certain coding techniques to ensure object disposal. These techniques include using the following in your code:
The Dispose and Close methods for the SPWeb object and SPSite object function in the same way. The Dispose method calls the object's Close method. MS recommends calling the Dispose method, instead of Close, because SPWeb and SPSite objects implement the IDisposable interface, and standard .NET Framework garbage collection calls the Dispose method to free any resources associated with the object from memory.
You can automatically dispose of SharePoint objects that implement the IDisposable interface by using the Microsoft Visual C# using statement.
String str;
using(SPSite oSPsite = new SPSite(http://server/))
{
using(SPWeb oSPWeb = oSPSite.OpenWeb())
}
}
void OpenWebNoLeak()
using (SPSite siteCollection = new SPSite(http://moss/))
{
using (SPWeb web = siteCollection.OpenWeb())
{
str = web.Title;
str = web.Url;
} // SPWeb object web.Dispose() automatically called.
} // SPSite object siteCollection.Dispose() automatically called.
}
// Do not do this. Dispose() is automatically called on SPWeb.
using( SPWeb web = SPControl.GetContextWeb(HttpContext.Current)) { ... }
{
// ... New SPSite will be leaked.
} // SPWeb object web.Dispose() automatically called.
Ex3
void SPControlBADPractice()
{
SPSite siteCollection = SPControl.GetContextSite(Context);
siteCollection.Dispose(); // DO NOT DO THIS
SPWeb web = SPControl.GetContextWeb(Context);
web.Dispose(); // DO NOT DO THIS.
}
If you create the object with a new operator, ensure that the creating application disposes of it.
Ex1
void CombiningCallsBestPractice()
{
//Perform operations on site.
} // SPWeb object web.Dispose() automatically called.
} // SPSite object siteCollection.Dispose() automatically called.
}
{
{
//Perform operations on site.
} // SPWeb object web.Dispose() automatically called; SPSite object
// siteCollection.Dispose() automatically called.
}
public static void SPSiteCollectionForEachBestPractice()
{
string sUrl = http://rajtestsite/
using (SPSite siteCollectionOuter = new SPSite(sUrl))
SPSiteCollection siteCollections = webApp.Sites;
SPSite siteCollectionInner = null;
foreach (siteCollectionInner in siteCollections)
{
try //Should be first statement after foreach.
//Exception occurs here.
}
finally
{
if(siteCollectionInner != null)
siteCollectionInner.Dispose();
}
}
}
} // SPSite object siteCollectionOuter.Dispose() automatically called.
}
Ex 3
void SPControlBestPractice()
{
SPSite siteCollection = SPControl.GetContextSite(Context);
SPWeb web = SPControl.GetContextWeb(Context);
// Do NOT call Dispose().
}
{
SPWebApplication webApp = new SPSite("http://moss").WebApplication;
SPSiteCollection siteCollections = webApp.Sites;
using (SPSite siteCollection = siteCollections.Add("sites/myNewSiteCollection", "DOMAIN\\User",
rajan@ms.com))
{
} // SPSite object siteCollection.Dispose() automatically called.
}
Same for webcollection.Add methods too.
Ex4
It is no longer advisable to call the Dispose method on the SPSite.RootWeb property whenever any of these properties are used.
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's obtained from SPContext.Current.Site.
}
It is no longer advisable to call the Dispose method on SPWeb.ParentWeb property whenever any of these properties are used.
using (SPSite site = new SPSite(http://localhost/))
{
using (SPWeb web = site.OpenWeb())
{
}
}
Ex 5
SPWeb.Webs Property
The SPWeb.Webs property returns an SPWebCollection object. The SPWeb objects in this collection must be disposed.
void WebsNoLeak()
{
using (SPSite siteCollection = new SPSite(http://moss/))
{
foreach (SPWeb innerWeb in outerWeb.Webs)
if(innerWeb != null)
innerWeb.Dispose();
}
}
}
public class CrossMethodLeak
{
private SPSite _siteCollection = null;
private SPWeb _web = null;
public void MethodA()
{
_siteCollection = new SPSite(http://moss/);
_web = _siteCollection.OpenWeb();
}
if (_web != null)
{
string title = _web.Title;
}
}
public void MethodC()
{
}
}
We can employ certain coding techniques to ensure object disposal. These techniques include using the following in your code:
- Dispose method
- using clause
- try, catch, and finally blocks
The Dispose and Close methods for the SPWeb object and SPSite object function in the same way. The Dispose method calls the object's Close method. MS recommends calling the Dispose method, instead of Close, because SPWeb and SPSite objects implement the IDisposable interface, and standard .NET Framework garbage collection calls the Dispose method to free any resources associated with the object from memory.
You can automatically dispose of SharePoint objects that implement the IDisposable interface by using the Microsoft Visual C# using statement.
String str;
using(SPSite oSPsite = new SPSite(http://server/))
{
using(SPWeb oSPWeb = oSPSite.OpenWeb())
{
str = oSPWeb.Title;
str = oSPWeb.Url; }
}
void OpenWebNoLeak()
{
String str;using (SPSite siteCollection = new SPSite(http://moss/))
{
using (SPWeb web = siteCollection.OpenWeb())
{
str = web.Title;
str = web.Url;
} // SPWeb object web.Dispose() automatically called.
} // SPSite object siteCollection.Dispose() automatically called.
}
Bad coding practices
Ex1 // Do not do this. Dispose() is automatically called on SPWeb.
using( SPWeb web = SPControl.GetContextWeb(HttpContext.Current)) { ... }
Ex2
using (SPWeb web = new SPSite(SPContext.Current.Web.Url).OpenWeb()){
// ... New SPSite will be leaked.
} // SPWeb object web.Dispose() automatically called.
Ex3
void SPControlBADPractice()
{
SPSite siteCollection = SPControl.GetContextSite(Context);
siteCollection.Dispose(); // DO NOT DO THIS
SPWeb web = SPControl.GetContextWeb(Context);
web.Dispose(); // DO NOT DO THIS.
}
Good practices
Thumb ruleIf you create the object with a new operator, ensure that the creating application disposes of it.
Ex1
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.
}
If we are not performing any operations on the SPSite object, we could write this more succinctly, as in the following code example.
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.
}
Ex2
Try and finally blocks or a using statement would be required to avoid potential leaks when you create a disposable object within a foreach block,public static void SPSiteCollectionForEachBestPractice()
{
string sUrl = http://rajtestsite/
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.
}
Ex 3
void SPControlBestPractice()
{
SPSite siteCollection = SPControl.GetContextSite(Context);
SPWeb web = SPControl.GetContextWeb(Context);
// Do NOT call Dispose().
}
Ex4
void SPSiteCollectionAddNoLeak(){
SPWebApplication webApp = new SPSite("http://moss").WebApplication;
SPSiteCollection siteCollections = webApp.Sites;
using (SPSite siteCollection = siteCollections.Add("sites/myNewSiteCollection", "DOMAIN\\User",
rajan@ms.com))
{
} // SPSite object siteCollection.Dispose() automatically called.
}
Same for webcollection.Add methods too.
Ex4
SPSite.RootWeb Property & SPWeb.ParentWeb Property
It is no longer advisable to call the Dispose method on the SPSite.RootWeb property whenever any of these properties are used.
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's obtained from SPContext.Current.Site.
}
It is no longer advisable to call the Dispose method on SPWeb.ParentWeb property whenever any of these properties are used.
using (SPSite site = new SPSite(http://localhost/))
{
using (SPWeb web = site.OpenWeb())
{
SPList list = web.Lists["Announcements"];
SPWeb parentWeb = list.ParentWeb; //No explicit dispose required.}
}
Ex 5
SPWeb.Webs Property
The SPWeb.Webs property returns an SPWebCollection object. The SPWeb objects in this collection must be disposed.
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.}
Cross Method Dispose Patterns
The following example demonstrates the common practice of holding onto the SPSite and SPWeb objects across methods in a class. Sometimes this design pattern is required, but ensure that you do not overlook the appropriate time to call Dispose when you are finished with the cross method calls. The following code example shows a pattern where SPSite and SPWeb leak when the class goes out of scope.
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;
}}
}
Conclusion
Because many SharePoint objects implement the IDisposable interface, you must take care when using these objects to avoid retaining them in memory. You can read the completed article here
No comments:
Post a Comment