Search All Articles Submit your Website or Blog to A New Internet Library
Saturday, March 20, 2010
SharePoint Coding Practices
Memory used by some SharePoint objects, primarily the SPSite and SPWeb objects, cannot be automatically freed up by the runtime. This can cause problems, since every such object may account for 1-2 MB. Also, these objects are often created automatically and more or less intuitively. Therefore, we need to always manually dispose some of the SharePoint objects.
For most objects, this can be done by
· Calling Dispose(): This works in most scenarios and are considered best practice. Ideally, this should be put within a “final” clause so we are sure it is always run even if preceding code fails. If possible, use “using” instead of calling Dispose()!
· Declaring the disposable object with “using”: This is also considered best practice. The compiler converts this into a try-catch-finally clause and puts a Dispose() call in the finally clause. “Using” is also best practice just like calling Dispose(), but because of the automatic creation of a “finally” clause, and because it makes the code slightly more readable, “using” is preferred over calling Dispose()! However, “using” is not applicable in all cases, such as when looping through a SPSiteCollection or SPWebCollection. The examples throughout this document use “using” whenever possible.
· Calling Close(): This May work fine for many objects, but it is not recommended in any scenario where Dispose() or “using” is available.
Methods and properties
The following declarations, methods and properties create or returns new objects which must be disposed before they leave their scope to avoid leaking memory. Note that when accessing properties (RootWeb, Parent, etc), new objects are automatically created.
| Method or property: | What to dispose? |
| new SPSite() | The returned SPSite |
| new SPGlobalAdmin() | The returned SPGlobalAdmin |
| new SPLimitedWebPartManager() | The returned SPLimitedWebPartManager |
| SPSite.OpenWeb() | The returned SPWeb |
| SPSite.SelfServiceCreateSite() | The returned SPSite |
| SPList.ParentWeb | The returned SPWeb |
| SPWeb.ParentWeb | The returned SPWeb |
| SPSite.RootWeb | The returned SPWeb |
| WebPartPage.RootWeb | The returned SPWeb |
The following properties and methods returns references to existing objects, and must not be disposed.
| Method or property: | |
| SPControl.GetContextSite() | |
| SPControl.GetContextWeb() | |
| SPContext.Current.Site | |
| SPContext.Current.Web | |
| SPContext.Site | |
| SPContext.Web | |
The lists above are far from complete; When any SharePoint object is accessed or returned, consideration should always be taken to whether the returned object should be disposed or not.
Warning: New objects are created even when not storing the reference to them. In the lines below, new objects are created, which must - but cannot - be disposed:
str = site.OpenWeb().Title; // do not do this!
str = site.RootWeb.url; // do not do this!
Warning: Accessing RootWeb or ParentWeb on any of the SPContext subobjects, still requires RootWeb/ParentWeb to be disposed. For example,
If you access: SPContext.Current.Site.RootWeb
You should dispose: SPContext.Current.Site.RootWeb
But should NOT dispose: SPContext.Current.Site
It is safe to dispose an object which has already been disposed.
| Bad practice (leaks!) | Best practice (no leaks) |
| Public void anyMethod() { SPSite site = new SPSite(); SPWeb web = site.OpenWeb(); // ... } // both web and site leaked! | Public void anyMethod() { using (SPSite site = new SPSite()) { using (SPWeb web = site.OpenWeb()) { // ... } } } |
| Public void anyMethod() { // this SPSite leaks: using (SPWeb web = new SPSite(...).OpenWeb(...)) { // ... } } | Public void anyMethod() { using (SPSite site = new SPSite(...)) { using (SPWeb web = site.OpenWeb(...)) { // ... } } } |
| public void anyMethod() { SPSite site; while (...) { site = new SPSite(); // ... } site.Dispose(); // every object except the last one leaked! } | public void anyMethod() { SPSite site; while (...) { site = new SPSite(); // ... site.Dispose(); } } |
| public void anyMethod() { using (SPSite site = SPContext.Current.Site) { // ... } // oups, we disposed a shared object!! } | public void anyMethod() { SPSite site = SPContext.Current.Site; // ... } |
| public void anyMethod() { using (SPSite site = new SPSite()) { site.RootWeb.Url = “New Title”; } } // site disposed properly, but ParentWeb leaked! | public void anyMethod() { using (SPSite site = new SPSite()) { using (SPWeb rootWeb = site.RootWeb) { rootWeb.title = “New Title”; } } } |
| public string anyMethod(SPListItem item) { // ... return item.ParentList.ParentWeb.Url; } // ParentWeb leaked! | public string anyMethod(SPListItem item) { string returnValue; using (SPWeb parentWeb = item.ParentList.ParentWeb) { returnValue = parentWeb.Url; } return returnValue; } |
| public string anyMethod() { return SPContext.Current.Site.RootWeb.Url; } | public string anyMethod() { string returnValue; using (SPWeb parentWeb = SPContext.Current.Site.RootWeb) { returnValue = parentWeb.Url; } return returnValue; } |
Collections
Many methods and properties has types of SPSiteCollection or SPWebCollection, such as:
· SPSite.AllWebs (Field: SPWebCollection)
· SPWeb.Webs (Field: SPWebCollection)
· SPWeb.GetSubwebsForCurrentUser (Return value: SPWebCollection)
It is easy to believe those returned collections contain existing SPSite and SPWeb objects, but these are actually created upon access on individual items. This must be remembered when using for each to loop through the collection, accessing a specific index, or adding an item to the collection – in all cases, the accessed or added object must be disposed.
| Bad practice (leaks!) | Best practice (no leaks) |
| public void anyMethod(SPWeb web) { foreach (SPWeb web in web.GetSubWebsForCurrentUser(...)) { // ... } } // every web leaked! | public void anyMethod(SPWeb web) { foreach (SPWeb web in site.GetSubWebsForCurrentUser(...)) { // .... web.Dispose(); // we can’t use “using” here } } |
| public void anyMethod() { SPSiteCollection siteColl = ...; siteColl[0].Title = “New Title”; } // siteColl [0] was created but never disposed! | public void anyMethod() { SPSiteCollection siteColl = ...; using (SPSite web = siteColl[0]) { web.Title = “New Title”; } } |
| public void anyMethod() { SPSite site = SPControl.GetContextSite(...); site.AllWebs.Add( ... ); } | public void anyMethod() { SPSite site = SPControl.GetContextSite(...); using(SPWeb web = site.AllWebs.Add( ... )) { // ... } } |
Special cases
There are a number of members and methods which will create new objects, whos disposal must be made in an unusual way. Here is a list which should cover most of them:
| Type | Method/field | Requires |
| SPLimitedWebPartManager | (Any use) | (object).web.Dispose(); |
| SPList | BreakRoleInheritance() | (object).ParentWeb.Dispose(); |
| SPWeb | LockIssue | (object).RootWeb.Dispose(); |
| SPWeb | Owner | (object).RootWeb.Dispose(); |
| SPWeb | SecondaryContact | (object).RootWeb.Dispose(); |
| PublishingWeb | GetPublishingWebs() | Each accessed item must be disposed by calling its Close(). |
| PublishingWebCollection | Add() | Returned object must be disposed by calling Close(). |
Also Read other Top Articles
- JSON Serialization in VS 2008
- Implementing Forms Authentication in Silverlight Application.
- Making GridView Rows or Individual Cells Clickable and Selectable.
- Enabling browser back button for GridView Paging and Sorting in Ajax 1.1 and 3.5 (using Visual Studio 2005/ Visual studio 2008)
- How to pass values from User Control to Page or calling Page methods from User Control.
- What is WCF?
- New features in C# 4.0
- C# to VB.NET and VB.NET to C# online free converter tools.


No comments:
Post a Comment
Post your comments/questions/feedback for this Article.