interviews.dotnetthread.com

↑ Grab this Headline Animator

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().

Submit this story to DotNetKicks

1 comment:

Adapt software India said...

SharePoint Online delivers the powerful features of SharePoint without the associated overhead of managing he infrastructure on your own. Flexible management options ensure that you still retain the
control you need to meet the compliance requirements of your organization. You can purchase SharePoint in the cloud as a standalone offering or as part of an Office 365 suite where you could also get access to Exchange, Lync, the Office clients and web apps.

Sharepoint developer
Sharepoint Site
Sharepoint Services
Sharepoint Designer
Sharepoint Consulting
Sharepoint Server

Post a Comment

Post your comments/questions/feedback for this Article.

 

Latest Articles