Category Archives: Software Development

The main theme of this blog: SharePoint, C#, ASP.NET, yada, yada

Development Setup for SP2010

Some important points to remember when developing against SP2010:

  • Make sure your Visual Studio project is set up for .NET 3.5, not .NET 4.0
  • Run Visual Studio as an Administrator to load debugging symbols
  • Make sure your project is set to compile for Any CPU or x64 (not x86 by default), otherwise your code will throw a FileNotFoundException

From the SharePoint 2010 book I’m reviewing

Balsamiq Mockups makes for easy UI design

We’ve been using Balsamiq Mockups for some time at my day job, but until recently I hadn’t used the tool heavily on any of the projects I’d been working.  Today I needed to shell out an example search results page for a project I am architecting in SharePoint.

Think of Balsamiq Mockups as Visio for the layman – it’s light, easy to use, not cluttered with unnecessary functionality, and runs on Adobe Air.  The presentation is something akin to what you might mockup on a whiteboard in the office and the end result, although a signature of the Balsamiq development team, is crisp and ideal for any document deliverable.

What I like about the tool most is that I was able to complete a mockup, which is functional for discussion purposes and doubles for architecture documentation, and it took me a fraction of the time I’d have spent in Visio – this gave me time to write this blog post.

At a price of $79, the product is a steal for the time it’ll save you.

Check out my finished page mockup:

Global Search Results

Ctrl-F Crash in Visual Studio

I have Resharper 4 installed into Visual Studio 2008.  On 64-bit the CTRL-F functionality crashes the application, which has driving me nuts.  My colleague Anand posted a solution to our company Intranet, so I stole his post for my blog for future reference. 

Thanks Anand 😉

“Visual Studio might crash when using the Find feature on a 64 bit system. This msdn article explains the issue. KB947841 I uncovered this problem after installing resharper on a 64-bit system, however, it is not related to resharper. Installing this add-in simply uncovers this bug in visual studio. You need to request this hotfix ”

Efficient way to add a new item to a SharePoint list

Never use SPList.Items.Add because this approach gets all items in the list before adding a new SPListItem.  Use the following method instead, which does not preload the list items:

   1:  /// <summary>
   2:          /// More efficient way of adding an item to a list.
   3:          /// </summary>
   4:          /// <remarks>
   5:          /// GetItems with a query is faster than calling the OM to get all items.
   6:          /// This is because the SPListItemCollection is created without loading all the
   7:          /// data until the first query request.  Whereas SPList.Items loads all the data
   8:          /// at construction.
   9:          /// </remarks>
  10:          /// <param name="list">List.</param>
  11:          /// <returns>List Item Added.</returns>
  12:          public static SPListItem OptimizedAddItem(SPList list)
  13:          {
  14:              const string EmptyQuery = "0";
  15:              SPQuery q = new SPQuery {Query = EmptyQuery};
  16:              return list.GetItems(q).Add();
  17:          }

SharePoint Development Best Practices (Summary)

I’ve read several blog posts of late regarding best practices for developing SharePoint API based components.  Some developers are aware of issues surrounding disposal of SPSite and SPWeb objects and the use of SPList Item collections, and some are not.  The simple fact is the SharePoint API is not intuitive when it comes usage of memory hungry-object instances, and it is all too easy to leave too many of these objects in memory for the garbage collector to deal with – causing large memory spikes in the site application pool with high traffic utilization.  Furthermore, what seems like innocent well structured code can perform badly because of the underlying calls against the SharePoint content databases.  This blog post serves as a reference point and as a quick summary of some of the best practices.

Best Practices: Using Disposable Windows SharePoint Services Objects

Reference

Enable the following registry setting to populate the ULS logs with allocation identifiers to isolate non-disposed SPSite and SPWeb objects:
HKEY_LOCAL_MACHINESOFTWAREMicrosoftShared ToolsWeb Server ExtensionsHeapSettings SPRequestStackTrace = 1

Wrap all calls that create a new SPSite or SPWeb object (except those from obtained from the SPContext.Current singleton) in try, catch, finally blocks, or using statements

SPContext objects are managed by the SharePoint framework and should not be explicitly disposed in your code. This is true also for the SPSite and SPWeb objects returned by SPContext.Site, SPContext.Current.Site, SPContext.Web, and SPContext.Current.Web.

You must be cautious and aware of what the runtime is doing whenever you combine SharePoint object model calls on the same line. Leaks arising from this scenario are among the hardest to find.

The finally block executes after calls to Response.Redirect in the try block. Response.Redirect ultimately generates a ThreadAbortException. When this exception is raised, the runtime executes all finally blocks before ending the thread. However, because the finally block can do an unbounded computation or cancel the ThreadAbortException, there is no guarantee that the thread will end. Therefore, before any redirection or transfer of processing can occur, you must dispose of the objects. If your code must redirect, implement it in a way similar to the following code example.

String str;
SPSite oSPSite = null;
SPWeb oSPWeb = null;

try
{
oSPSite = new SPSite("http://server");
oSPWeb = oSPSite.OpenWeb(..);

str = oSPWeb.Title;
if(bDoRedirection)
{
if (oSPWeb != null)
oSPWeb.Dispose();

if (oSPSite != null)
oSPSite.Dispose();

Response.Redirect("newpage.aspx");
}
}
catch(Exception e)
{
}
finally
{
if (oSPWeb != null)
oSPWeb.Dispose();

if (oSPSite != null)
oSPSite.Dispose();
}

 

Good practices to reduce object long-term retention:

  • If you create the object with a new operator, ensure that the creating application disposes of it.
  • Dispose of items created by SharePoint methods that return other SPWeb objects (such as OpenWeb).
  • Do not share any SPRequest object (and by extension any object that contains a reference to an SPRequest object) across threads.

SPSite Object:

  • The SPSiteCollection.Add method creates and returns a new SPSite object. You should dispose of any SPSite object returned from the SPSiteCollection.Add method.
  • The SPSiteCollection [] index operator returns a new SPSite object for each access. An SPSite instance is created even if that object was already accessed. The following code samples demonstrate improper disposal of the SPSite object.
  • The SPSite.AllWebs.Add method creates and returns an SPWeb object. You should dispose of any SPWeb object returned from SPSite.AllWebs.Add.
  • The SPWebCollection.Add method creates and returns an SPWeb object that needs to be disposed.
  • The SPSite.AllWebs [] index operator returns a new SPWeb instance each time it is accessed.
  • The OpenWeb method and SelfServiceCreateSite method (all signatures) create an SPWeb object and return it to the caller.
  • The Microsoft.Office.Server.UserProfiles.PersonalSite returns an SPSite object that must be disposed.
SPSite.RootWeb Property

An earlier version of this article indicated that the calling application should dispose of the SPSite.RootWeb property just before disposing of the SPSite object that is using it. This is no longer the official guidance. The dispose cleanup is handled automatically by the SharePoint framework. Additionally, SPSite properties LockIssue, Owner, and SecondaryContact used the RootWeb property internally. Given the updated guidance for RootWeb, it is no longer advisable to call the Dispose method on the SPSite.RootWeb property whenever any of these properties are used.

SPWeb Object:

  • The SPWeb.Webs property returns an SPWebCollection object. The SPWeb objects in this collection must be disposed.
  • The SPWeb.Webs.Add method (or Add) creates and returns a new SPWeb object. You should dispose of any SPWeb object returned from this method call.
  • The SPWeb.Webs[] index operator returns a new SPWeb object for each access
SPWeb.ParentWeb Property

Updated Guidance

An earlier version of this article recommended that the calling application should dispose of the SPWeb.ParentWeb. This is no longer the official guidance. The dispose cleanup is handled automatically by the SharePoint framework.

Other Objects:

  • Microsoft.SharePoint.Portal.SiteData.Area.Web Property.  The Web property returns a new SPWeb object each time it is accessed.
  • If the object is obtained from the SharePoint context objects (GetContextSite method and GetContextWeb method), the calling application should not call the Dispose method on the object.
  • The SPLimitedWebPartManager class contains a reference to an internal SPWeb object that must be disposed.
  • The GetPublishingWebs method of the PublishingWeb class returns a PublishingWebCollection object. You must call the Close method on each enumerated innerPubWeb object. When you are calling only the GetPublishingWeb method, you are not required to call Close.
  • The Microsoft.SharePoint.Publishing.PublishingWeb.GetVariation method returns a PublishingWeb object that must be disposed.

Best Practices: Common Coding Issues When Using the SharePoint Object Model

Reference

Caching Data and Objects

Many developers use the Microsoft .NET Framework caching objects (for example, System.Web.Caching.Cache) to help take better advantage of memory and increase overall system performance. But many objects are not "thread safe" and caching those objects can cause applications to fail and unexpected or unrelated user errors.

Caching SharePoint Objects That Are Not Thread Safe

You might try to increase performance and memory usage by caching SPListItemCollection objects that are returned from queries. In general, this is a good practice; however, the SPListItemCollection object contains an embedded SPWeb object that is not thread safe and should not be cached.

You can cache a DataTable object that is created from the SPListItemCollection object.

Using Objects in Event Receivers

Do not instantiate SPWeb, SPSite, SPList, or SPListItem objects within an event receiver. Event receivers that instantiate SPSite, SPWeb, SPList, or SPListItem objects instead of using the instances passed via the event properties can cause the following problems:

  • They incur significant additional roundtrips to the database. (One write operation can result in up to five additional roundtrips in each event receiver.)
  • Calling the Update method on these instances can cause subsequent Update calls in other registered event receivers to fail.

Working with Folders and Lists

Do not use SPList.Items.  SPList.Items selects all items from all subfolders, including all fields in the list.

  • Instead of calling SPList.Items.Add, simply use SPList.AddItem.
  • Retrieve list items using SPList.GetItems(SPQuery query)
  • Instead of using SPList.Items.GetItemById, use SPList.GetItemById(int id, string field1, params string[] fields)

Do not enumerate entire SPList.Items collections or SPFolder.Files collections.

Poor Performing Methods and Properties Better Performing Alternatives
SPList.Items.Count SPList.ItemCount
SPList.Items.XmlDataSchema Create an SPQuery object to retrieve items you want
SPList.Items.NumberOfFields Create an SPQuery object (specifying the ViewFields)
SPList.Items[System.Guid] SPList.GetItemByUniqueId(System.Guid)
SPList.Items[System.Int32] SPList.GetItemById(System.Int32)
SPList.Items.ReorderItems Perform a non-paged query using SPQuery in each page
SPList.Items.GetItemById(System.Int32) SPList.GetItemById(System.Int32)
SPFolder.Files.Count SPFolder.ItemCount

Use PortalSiteMapProvider (Microsoft Office SharePoint Server 2007 only).

Steve Peschka's white paper Working with Large Lists in Office SharePoint Server 2007 describes an efficient approach to retrieving list data in Office SharePoint Server 2007 by using the PortalSiteMapProvider class.

(Very important as this works around the 2000 item limit)

Scaling Code

How to make this code more scalable or fine-tune it for a multiple user environment can be a hard question to answer. It depends on what the application is designed to do.

You should take the following into consideration when asking how to make code more scalable:

  • Is the data static (seldom changes), somewhat static (changes occasionally), or dynamic (changes constantly)?

  • Is the data the same for all users, or does it change? For example, does it change depending on the user who is logged on, the part of the site being accessed, or the time of year (seasonal information)?

  • Is the data easily accessible or does it require a long time to return the data? For example, is it returning from a long-running database query or from remote databases that can have some network latency in the data transfers?

  • Is the data public or does it require a higher level of security?

  • What is the size of the data?

  • Is the SharePoint site on a single server or on a server farm?

Using SPQuery Objects

SPQuery objects can cause performance problems whenever they return large result sets. The following suggestions will help you optimize your code so that performance will not suffer greatly whenever your searches return large numbers of items.

  • Do not use an unbounded SPQuery object.
  • An SPQuery object without a value for RowLimit will perform poorly and fail on large lists. Specify a RowLimit between 1 and 2000 and, if necessary, page through the list.
  • Use indexed fields.
  • If you query on a field that is not indexed, the query will be blocked whenever it would result in a scan of more items than the query threshold (as soon as there are more items in the list than are specified in the query threshold). Set SPQuery.RowLimit to a value that is less than the query threshold.
  • If you know the URL of your list item and want to query by FileRef, use SPWeb.GetListItem(string strUrl, string field1, params string[] fields) instead.

Authentication failed because the remote party has closed the transport stream

If you receiver the error "Authentication failed because the remote party has closed the transport stream" when accessing "Search Settings" in the SSP, the following steps will resolve the issue.  The issue is a result of incorrect self-serving-certificate.

1. Install the IIS 6.0 Resource Kit on the index server (http://www.microsoft.com/downloads/details.aspx?FamilyID=56fc92ee-a71a-4c73-b628-ade629c89499&DisplayLang=en)
2. Assign a new SSL certificate  to the Office SharePoint Server Web Services site on the index server using the SELFSSL tool from the resource kit.

SELFSSL.EXE /N:CN=<name of index server> /K:1024 /V:<number of days cert should be valid> /S:951338967  /P:56738
The /S and /P parameters specify the web site ID and port number, respectively, of the Office SharePoint Server Web Services site in IIS. They should be set to the appropriate values for your environment.

Recycle IIS App Pool from Script

My colleague, Carlos Fernandez, sent me this CSCRIPT command for recycling the an IIS application pool:

%windir%system32cscript.exe c:windowssystem32iisapp.vbs /a "SharePoint – 80" /r

Tired of manually recycling the app pool each time you make a code change to your SharePoint web part?  No problem, add the following command to the post build events in Visual Studio.

Debugging SharePoint, which Process?

When developing 3rd party components for SharePoint you cannot avoid debugging.  Debugging usually involves attaching to a W3WP.EXE process – IIS host for a SharePoint application, from within Visual Studio. 

When presented with the attach to process dialog box, you should typically see two to three instances of W3WP.EXE, one for central administration site, maybe another for the SSP administration site, and one for your web application:

image

So.. which process should you attach?  Most developers (myself included) attach to all – just to be sure.  But what if you want to know exactly which process to attach? 

My colleague – Kevin Vieira gave made me aware of IISAPP.EXE – a nice built in tool to list all of IIS hosted web applications with associated PID:

W3WP.exe PID: 236   AppPoolId: SharePoint – 80
W3WP.exe PID: 244   AppPoolId: SharePoint – 5000
W3WP.exe PID: 3616   AppPoolId: SharePoint Central Administration v3

SharePoint Content Structure and Reports Limit

We ran into an interesting issue this week where all reports at the site collection level within "Content Structure and Reports" stopped working.  The log included the following error:

Query Execution threw SPException: The query cannot be completed because the number of lists in the query exceeded the allowable limit
  10/10/2008 11:38:19.16     w3wp.exe (0x09F8)                           0x07F8    CMS                               Site Management                   622h   
Unexpected    SMReportsData GetQueryResults – Query Execution threw SPException: The query cannot be completed because the number of lists in the query
exceeded the allowable limit. For better results, limit the scope of the query to the current site or list or use a custom column index to help reduce the number of lists.    

My esteemed colleague Carlos Fernandez uncovered the following fix…

image

The default lists limit for the query generated by these reports is a 1000, so running the reports at the site collection level caused SharePoint to exceed this amount when the site contained more than 1000 page libraries.  Populating the CAML List Type with:

<Lists BaseType="1" MaxListsLimit="0"/>