Sunday 22 June 2008

Content Deployment Wizard updated - Release 1.0

I've released a new version of the Content Deployment Wizard today, labelled as 'Release 1.0'. This release adds only minor changes to beta 2, and is mainly intended to pave the way for a future beta release which will contain new functionality. However I also want to communicate that the current codebase is now stable, since I heard feedback from some folks saying the 'beta' label was putting some people off (e.g. non-technical clients of SharePoint consultants).

That said, the following minor updates have been incorporated:

  • ability to modify which lists are filtered out of the treeview:

    Certain 'system'-type lists are not shown in the treeview as they are generally not relevant to import/export operations, but on occasion you may want to 'unhide' some lists e.g. 'Variation Labels' and 'Relationships List' lists if you are using variations. See the readme.txt file for instructions on how to do this

  • minor bug fixes e.g. .cmp file now correctly saved with extension if a period (.) is present in your chosen filename, validation to prevent child objects being added from treeview when parent site collection already added

The new version can be downloaded from www.codeplex.com/SPDeploymentWizard.

Future development

Work is underway on the next release of the Wizard, with the main emphasis being on:

  • allowing import/export operations to be scripted
  • allowing settings used in an operation to be saved to a file for easy reuse
  • support for incremental deployments (hopefully!)

If you have other suggestions, I can't guarantee I can include them in the next release but I'd certainly be interested to hear.

Sunday 15 June 2008

Disposing SharePoint objects - what they don't tell you

If you're a SharePoint developer and find yourself regularly writing code to work with SPListItem objects, here's some info which might help you factor your code in a slightly neater way in some scenarios.  Interestingly this doesn't get mentioned in any of the key papers/articles - I can think of a good reason for this (which we'll look at), but in my mind this is a safe technique. If you have other ideas however, I'd love to hear from you.

Most developers are now fairly well-versed in the techniques needed to write efficient SharePoint code (key resources are listed at the end of the article), specifically in terms of disposing of any SPSite/SPWeb objects your code creates. The thing is, having to always be mindful of disposing these objects can sometimes restrict us in the way we want to write our code - consider the following simplified example:

public void DoSomething()
{
SPList list = getList();

// do something with list..
foreach (SPListItem item in list.Items)
{
processItem(item);
}

// ** PROBLEM - how do we now dispose of the SPSite/SPWeb objects we created earlier? **
}

private SPList getList()
{
// can't dispose of these objects here if we're returning a list - we'll be attempting to use
// objects which have already been disposed of..
SPSite site = new SPSite("http://cob.blog.dev");
SPWeb web = site.OpenWeb("/MyWeb");
SPList list = web.Lists["MyList"];

return list;
}


The problem here is we created our SPSite/SPWeb objects in a different method to where we need to dispose them - this can happen a lot when writing library code. To extend this example, here's a pattern I regularly use to ensure I'm getting my objects the most efficient way - using SPContext if it's present, but instantiating them myself if it isn't (i.e. the code is called from an event receiver, console app etc.):


public void DoSomething()
{
bool bDisposalsRequired = false;

// get list from SPContext if we have one..
SPList list = getListFromContext();
if (list == null)
{
// otherwise get list from objects we create..
list = getInstantiatedList();
bDisposalsRequired = true;
}

// do something with list..
foreach (SPListItem item in list.Items)
{
processItem(item);
}

if (bDisposalsRequired)
{
// ** PROBLEM - how do we now dispose of the SPSite/SPWeb objects we created earlier? **
}
}

private SPList getInstantiatedList()
{
// can't dispose of these objects here if we're returning a list - we'll be attempting to use
// objects which have already been disposed of..
SPSite site = new SPSite("http://cob.blog.dev");
SPWeb web = site.OpenWeb("/MyWeb");
SPList list = web.Lists["MyList"];

return list;
}

private SPList getListFromContext()
{
SPContext currentContext = SPContext.Current;
SPList list = null;

if (currentContext != null)
{
list = currentContext.Site.AllWebs["MyWeb"].Lists["MyList"];
}

return list;
}


When the code starts to become more complex like this, we start to really want a simple way of disposing the objects we created elsewhere. I'd probably caution against this, but what happens if you created the SPSite/SPWeb objects not only in another method, but another class? All of a sudden disposing of objects correctly is a lot more complex than the examples given in the white papers. 

Now, the savvy SharePoint developer might think "Hold on, the SPList has a ParentWeb object (and SPListItem has a ParentList object!), what happens if I go up the hierarchy and dispose that way?" - code to this would look like:


if (bDisposalsRequired)
{
list.ParentWeb.Dispose();
list.ParentWeb.Site.Dispose();
}


Now how would we know the correct objects have been disposed? Are these objects the same objects we were using earlier? Or has SharePoint populated these properties with references to different objects, meaning we've left our original objects alive and could run into scalability problems?

Well, the good news is these are the same objects, so disposing in this way will dispose of the objects you created. We can tell this by comparing the objects using System.Object's GetHashCode() method:


private void compareObjects()
{
SPSite site = new SPSite("http://cob.blog.dev");
SPWeb web = site.OpenWeb("/MyWeb");
SPList list = web.Lists["MyList"];

SPWeb parentWeb = list.ParentWeb;



// no message displayed..
Debug.Assert(parentWeb.GetHashCode() != web.GetHashCode(), "Objects are not same!");


// create a *new* SPWeb object and compare it to our other reference..
web = site.OpenWeb("/MyWeb");

// message IS displayed..
Debug.Assert(parentWeb.GetHashCode() != web.GetHashCode(), "Objects are not same!");
}


What we see from this is that the SPWeb object stored in the list.ParentWeb property has the same hash code as the original SPWeb object we created, but if we create a new instance of the same web, it has a different hash code. This indicates the objects in the first comparison are the same - so disposing of them through the ParentWeb reference will indeed dispose of the objects we created. So happy days - we've found we can factor our code in a way which may be more logical and readable.


The caveat

So why might this not be mentioned in any of the published guidance? Well, before using this technique throughout your code you should consider that in writing code in this way we are effectively relying on an internal implementation detail of the current SharePoint API. If Microsoft were to change this in a service pack (or the next version of SharePoint), our code may no longer dispose of objects correctly. I'd recommend giving this your own consideration (not least because you might conclude differently to me), but I'd suggest this change would be fairly unlikely. The reason for this is the SharePoint team themselves need to eliminate any unnecessary SPSite/SPWeb objects, so of course it makes sense that the the same SPWeb instance used to obtain the SPList is used to populate the ParentWeb variable. Creating an extra instance would make the API less efficient. On that basis, I personally am happy to write code in this way. If you think I've got this wrong (I can't guarantee I haven't), of course I'd love to hear from you.

In an upcoming article, I'll also discuss the idea of going beyond the MSDN examples, and trying to write SharePoint data access code in a more 'enterprise' or 'patterns' kind of way. Stay tuned for more on this.


Disposing SharePoint objects - required reading

Sunday 1 June 2008

Code/Feature samples for common SharePoint development tasks

There are lots of tools available to help developers, but I always think the single most useful thing is actually seeing a good example of the thing I'm trying to develop. This is why SharePoint blogs are so popular right? As well as checking my favorite blogs or past articles, I'm always going back to previous work - perhaps to see what values I used in a certain SharePoint file or to grab a chunk of code I wrote which I can amend to fit my current requirement. So today I want to point you in the direction of some useful samples which could be good reference material if you're a SharePoint developer - in actual fact I'm not releasing anything new here, but highlighting that my recent 'Config Store' solution provides a great "one-stop shop" of downloadable examples of several common SharePoint development tasks. Examples of the following dev tasks can all be found in the solution:

  • Deploy site columns, content types as Feature
  • Deploy a list (with default list items) as a Feature
  • Using Feature receivers
  • Using SPWebConfigModification to make web.config changes in code/as part of a Feature
  • Using SPQuery to efficiently find items in a list
  • Build a Solution package (.wsp) without WSP Builder
  • Write a Solution deployment script to retract Solution, deactivate Feature, redeploy Solution, activate Feature etc.
  • Using event receivers
  • As a .Net bonus, how to use the HttpRuntime class to work with ASP.Net caching outside of a web context

The entire set of code/Feature files can be downloaded from Codeplex, making it a great reference project containing samples of all the tasks listed above. If this is useful to you, the list below details the file to open to find the code sample, and some notes which might help you to get to grips with the task:

Deploy site columns, content types as Feature:

File

Notes

ConfigStoreElements.xml          

This is accomplished by use of the Field/ContentType Feature elements. Note these should be before any ListTemplate/ListInstance items in the same elements file - if using both sets of elements in different files, ensure the field/content type file is listed first in manifest.xml.



Deploy a list (with default list items) as a Feature:

File

Notes

ConfigStoreElements.xml          

This is accomplished by use of the ListTemplate/ListInstance Feature elements.



Feature receivers:

File

Notes

ConfigStoreFeatureReceiver.cs

In my case, the Feature receiver makes modifications to web.config and programmatically adds list event receivers to a list.



web.config modifications

File

Notes

ConfigStoreFeatureReceiver.cs

This is accomplished by use of the SPWebConfigModification class. I add three entries to the web.config to support my solution.

 

Using SPQuery to find items in a list:

File

Notes

ConfigStore.cs                                 

I have two methods in the ConfigStore class which perform queries in this way (also known as a CAML query).

 

Build a Solution package (.wsp) without WSPBuilder:

File

Notes

makecab.ddf/                                  
manifest.xml                          

Whilst WSPBuilder offers a great automated way to build Solutions, occasionally there is a need to step outside the tool to build the package 'manually'. In my case, I had a problem where WSPBuilder was adding elements in the 'wrong' order to the generated manifest.xml file, and this was causing the Solution deployment to fail.

 

Solution deployment script to retract Solution, deactivate Feature etc:

File

Notes

COB.SharePoint.Utilities.ConfigStore_Install.bat      

This is the script I've often used to deploy my Solutions. It has error checking at each stage so I can easily tell at what point the install fails for simpler problem diagnosis.

 

Using event receivers:

File

Notes

ConfigStoreListEventReceiver.cs

In the Config Store solution I use a list event receiver to add items to the cache when the list contents change. This code shows using the ItemAdded and ItemUpdated events on the list.

 

Using the HttpRuntime class to work with ASP.Net caching outside of ASP.Net:

File

Notes

ConfigStoreListEventReceiver.cs

Something to remember with list event receivers is that we actually don't have access to HttpContext.Current or SPContext.Current - both are null. If it wasn't for the HttpRuntime class, this would be a problem for my Config Store code since I wanted to add/remove items from the cache in the list event receiver (i.e. manage the cache as soon as list items are changed). Fortunately, HttpRuntime allows us access to the ASP.Net framework from any code location (e.g. console app).

 

The link to download all this stuff is at http://www.codeplex.com/SPConfigStore. Hope you find the samples useful, feel free to leave a comment if anything doesn't make sense.