Showing posts with label List Programming. Show all posts
Showing posts with label List Programming. Show all posts

Wednesday, 17 November 2010

How to determine if a SPPublishingPage is published

You can programmatically determine if the SPPublishingPage you're dealing with is in a published state by retrieving the SPFileLevel of the page's corresponding SPFile:

if (page.ListItem.File.Level == SPFileLevel.Published) …

You can also access this through the PublishingPage.ListItem.Level property.

The same SPFileLevel enumeration will also indicate if the page is in draft mode (checked in but not published) or checked out but in my experience this property will return SPFileLevel.Published or SPFileLevel.Draft more often than not.

To determine whether the page is checked out, use the SPFile.CheckOutStatus property in WSS 3.0 or the  SPFile.CheckOutType property in SP2010. Any value other than None means the page is checked out.

If you found this post helpful, please support my advertisers.

SPSite.AllWebs vs SPWeb.Webs

There's a subtle distinction between SPSite.AllWebs and SPWeb.Webs to be aware of—and yes, despite this being the SharePoint API we're talking about, it's more than just a naming oddity!

SPSite.AllWebs returns the immediate child webs of the site collection and all of their child webs (in other words, all webs recursively within the site collection); SPWeb.Webs has a much narrower scope and only returns the first level child webs immediately below the SPWeb object.

So what does this mean and how does it benefit you? If you're writing code that recursively walks the site hierarchy using SPWeb.Webs, you may be able to avoid the overhead by simply using SPSite.AllWebs. Recursion is fun and all but it adds complexity where it may not be warranted.

If you found this post helpful, please support my advertisers.

Thursday, 14 October 2010

The Mysterious SourceID Attribute

I see a lot field definitions around that unnecessarily include a SourceID attribute:

<Field
SourceID="http://schemas.microsoft.com/sharepoint/v3"

More often than not, the value of this attribute is set as above. Microsoft's own documentation samples tend to include this attribute.

So what does it do? Not a lot as far as I can tell; I don't include it with my own field definitions because inspecting the field after deployment with SharePoint Manager proves SharePoint sets it automatically with the GUID of the list that created the field. The Field Element documentation also indicates it is optional.

If you're intent on using it, the documentation describes this attribute as "containing the namespace that defines the field, such as http://schemas.microsoft.com/sharepoint/v3" so rather than use the default namespace it may be advisable to use your own (I haven't tried this myself).

If you found this post helpful, please support my advertisers.

Friday, 12 February 2010

Best Practice List Development in SharePoint

I had the honour of speaking on the subject of best practice SharePoint list development at last weekend’s SharePoint Saturday event held in Perth, Western Australia but I want to take this discussion one step further. I’m therefore creating this post to point to my slide deck from the event and as an index for follow-on, detailed posts about some of the items I had to gloss over. There’s precious little out there, in a single location, on the subject of list development guidelines and I’m hoping to change that. If you want to contribute what you feel is a best practice I’ve missed or challenge one of the practices I do have listed, please comment and join the discussion.

Slides are available here: Best Practices for Developing SharePoint Lists (PowerPoint | PDF)

Here are the two key resources I cite in the presentation:

Tuesday, 9 February 2010

westernaustralia.com Relaunch and Other Website Recent Activities

If you’ve been following the progress of the westernaustralia.com website over the years, you’ll already know the site was one of the first in Australia to be launched on the MOSS 2007 platform and has been consistently voted as one of the top fully branded SharePoint sites in the world ever since. Having worked on the site since the get-go and as the current technical lead for the project, I’m the proud owner of the site’s programmatic aspects; today I’m tickled pink to tell you, the SharePoint community, about yesterday’s launch of the new Tourism Western Australia brand, Experience Extraordinary, and, more specifically, the brand’s impact on the westernaustralia.com website.

At the moment we’re working with the Digital Marketing team on a two (or three phase) approach (depending on how you look at it) to implement the new brand. The first phase unfolded in August last year and involved the neutralisation of the preceding brand’s elements (The Real Thing) while the latest creative design agency, Host, was appointed. Phase 1 of the new brand implementation kicked off in the dev team a little over three weeks back and involved making the Photoshop mockups provided by Host into a living website. This work focused largely on the page banners (vibrant imagery, the tab, and extra height), the navigation, the background colour (trust me—everything is more complicated than you might think at first glance with wa.com!), what we call the ePostcards element, and the footer elements.

Here’s a picture of what I think is a visually stunning website and a vast improvement over its predecessor:

wacom homepage 4 Experience Extraordinary Phase 1

Phase 2 holds still more secrets but you can bet we’ll be making all the middle bits fit with the rest of the changes. One of the challenges we’ll be facing is getting the home page weight down from a whopping 1750KB and 100 requests. Stunning, certainly, but our CDN of choice (Akamai) allows us to get away with this sort of monkey business.

In addition to all the glam, we also took the opportunity to overhaul the heading infrastructure. This subsystem is designed to give content editors the ability to upload new banner images and all of the corresponding display data required to render the Flash banner. The Flash banner itself was built by Host from our previous banner and it takes as a parameter an XML file providing all the information it needs to display the banner images, text, links, and colours.

Obviously this data is stored in a list to which the FlashBanner.cs web part communicates at render time. Like I say, nothing in wa.com is as it first appears and one of the more complex requirements was allowing a subsite to override the banners displayed for for it and its children (in effect to support the major subsections of the site such as the destinations). Apart from simply walking up the site hierarchy recursively until a banner list is found, we then needed interrogate the list and emit an XML file acceptable to the banner; the URL to the file is finally cached with a dependency on the file itself.

Interestingly, this was one of the first times we started using event receivers on the banner lists to invalidate the cache when a banner is added, edited, or deleted; this keeps the content editors happy and productive and is one less of those annoying “is my banner cached in the browser cache | Akamai | reverse proxy| application cache | output cache | blob cache?” questions ;)

I’ll also point out we’re using a simple custom list for this instead of a picture library or custom list derived from a picture library. The previous version of this list was in fact a custom picture library but it suffered from broken thumbnails (which we now know how to fix) and proved rather cumbersome to use in practice (no reordering, a difficult view, etc). The move away from the picture library wasn’t, in retrospect, necessarily a great decision but it was probably the best decision at the time and came with considerable deliberation. The one major problem with the current approach is banner images must be uploaded separately to a real picture library and then referenced from the list; this is a bit of a double-up and disconnects the image itself from its metadata. As our understanding of list development and the peculiarities of these other list types increases, we may revisit this approach.

Also at a technical level, we recently move the site from our old IBM BladeCenter kit running Windows Server 2003 x86, MOSS 2007 SP1 (not even the Infrastructure Updates—gasp!), .NET 3.0, and a non-clustered SQL Server 2005 x86 database server. Everything was virtualised on ESX 4.0. We actually had three of these farms: one in prod, one in DR, and one for authoring; as content deployment never worked for the site, this meant a daily backup and restore of the content database from authoring to production and corresponding switch to or from DR (with DR actually being treated as a standby prod environment). That must have really sucked for our admin who had did that essentially manual task every business day since launch in May 2007. What. A. Drag.

From that setup, we moved to what was briefly the bees knees: Windows Server 2008 x64, MOSS 2007 SP2 + June 2009 CU, .NET 3.5 SP1, and a clustered SQL Server 2008 x64 database environment. Everything is still virtualised on ESX 4.0 and the entire setup is mirrored in DR. We’ve finally done away with the authoring farm so content editors are editing content in the production farm (we’re working towards a tiered security design and approval workflows, by the way, but our content editors have been working with the environment for years now and are mature in their understanding of how not to break the site ;). So no more daily content deployments and those of us in the dev team can finally start working with .NET 3.5 and LINQ.

For more on how we run the site, check out my Perth SharePoint User Group presentations and videos (things have changed but not that much):

http://blog.mediawhole.com/2009/02/how-we-do-wcm-at-tourism-wa-im-speaking.html

http://blog.mediawhole.com/2009/03/presenting-at-next-sharepoint-user.html

If you’ve read this far, you deserve the chance to win a prize. Want the opportunity to take an extraordinary taxi ride around the state of Western Australia? If so, check out the “brand activation” microsite: http://www.extraordinarytaxiride.com.au/

Note: I am employed by Tourism WA as a contractor working for Diversus. Mediawhole, mediawhole.com, and this blog are not associated directly with Tourism Western Australia or the westernaustralia.com website. The information provided above  is published independently as a member of the public and does not reflect the views of Tourism Western Australia or Diversus. Please consult a Tourism WA representative for more information about its brand, campaigns, and websites.

Saturday, 9 January 2010

I’m Speaking at SharePoint Saturday Perth this February

How exciting—our very first SharePoint Saturday event in Perth! A BIG shout out to Jeremy Thake for organising the venue, speakers, sponsors, prizes, and everything else! The speaker line-up looks fantastic and the sessions cover a range of topics so I reckon this is going to be a great day.

In addition to attending the event, I’ll also be presenting on the subject of SharePoint list development. Here’s the official blurb for my talk:

Lists are key to understanding the power of the SharePoint platform and provide core data storage and management facilities in a SharePoint environment. Lists can be customised to suit custom requirements but doing so isn’t always straightforward.

Learn how to create, deploy, manage, and interact with SharePoint lists in this jam-packed session. Discussion will cover the pros and cons of using SharePoint lists before focusing on methods for creating and deploying lists between environments in a repeatable manner; techniques for working with lists and data using the SharePoint API with also be demonstrated.

Existing experience with the SharePoint UI, a cursory knowledge of content types, and ASP.NET development experience is recommended but not assumed.

If there’s anything you’d like me to cover in particular please drop me a line or post a comment below. If all goes well I’ll also be recording the session so feel free to make a request or post a question even if you’re unable to attend in person.

Finally, Diversus are sponsoring the event and their package includes a JVC video camera to be given away—thanks guys!!!

Diversus - Perth SharePoint Development

Wednesday, 11 November 2009

After Event Receiver Doesn't Fire

Here we go again... note to self: because "after" events like ItemAdded and ItemUpdated fire asynchronously, testing the receiver wiring by doing something with a side effect (like throwing an exception) won't have any visible result within the context of the site (do check the event log though!).

Throwing within a before event like ItemAdding will bring the operation to a screeching halt.

Tuesday, 10 November 2009

Adding the Edit Control Block (ECB) to an additional/different list column

This is how I add the ECB menu to a different column. All changes are made within the context of my list's Schema.xml file.

To start, I already have a custom text field defined within the Fields element:

<Field
Description="$Resources:Field_Caption_Description;"
DisplaceOnUpgrade="TRUE"
DisplayName="$Resources:Field_Caption_DisplayName;"
Group="$Resources:Group_DefaultName;"
ID="{1ac83cea-5b25-4e2f-ae43-5116e005ca97}"
Name="Caption"
Type="Text"
/>

To this I add a new computed field that references the existing field:

<!-- Edit Control Block (ECB) Context Menu -->
<Field
AuthoringInfo="(with menu)"
ClassInfo="Menu"

DisplaceOnUpgrade="TRUE"
DisplayName="$Resources:Field_Caption_DisplayName;"
DisplayNameSrcField="Caption"
ID="{09868F6C-7419-4db3-9C1A-434598ABE010}"
Group="$Resources:Group_DefaultName;"
Name="CaptionContextMenu"
ReadOnly="TRUE"
Type="Computed"
>
<FieldRefs>
<!-- First FieldRef points to parent field -->
<FieldRef ID="{1ac83cea-5b25-4e2f-ae43-5116e005ca97}" Name="Caption" />

<FieldRef ID="{3c6303be-e21f-4366-80d7-d6d0a3b22c7a}" Name="_EditMenuTableStart" />
<FieldRef ID="{2ea78cef-1bf9-4019-960a-02c41636cb47}" Name="_EditMenuTableEnd" />
</FieldRefs>
<DisplayPattern>
<Field Name="_EditMenuTableStart" />
<HTML><![CDATA[<a onfocus="OnLink(this)" href="]]></HTML>
<URL />
<HTML><![CDATA[" ONCLICK="GoToLink(this);return false;" target="_self">]]></HTML>
<!-- Points to parent field -->
<Field Name="Caption" />

<HTML><![CDATA[</a>]]></HTML>
<Field Name="_EditMenuTableEnd" />
</DisplayPattern>
</Field>

Note DisplayNameSrcField points to the original field, as does the <Field> element in the DisplayPattern section.

Finally in my view's ViewFields element, I modify the FieldRef pointing to my original field to point to my ECB column:

<FieldRef Name="CaptionContextMenu" />

A few things to note:

  • When I first tried this with the original field set as type HTML, it didn't work; I ended up changing the field to a text field. I haven't tried other field types.
  • /_layouts/sitemanager.aspx presents the view in a similar but slightly different way to that presented by the list itself (e.g. /Lists/MyList/AllItems.aspx); Site Manager tends to always add the ECB on the second column whereas the latter tends to do a better job doing what you tell it to do. [Update: I use the DocIcon field in position #1 to work around this issue... it shows up as a little document icon with a column name of Type--which I haven't been able to hide. It's clickable in the AllItems.aspx-style view at least so not completely useless and it obviously shoves the ECB to a potentially meaningful field in the second position (you can alternatively use ID but this may not not make sense if you're ordering list items).]

Monday, 9 November 2009

ContentTypeRef vs ContentTypeBinding

There seems to be some uncertainty around the use of the ContentTypeRef element in Schema.xml and the ContentTypeBinding element in your elements file. The master—Andrew Connell—indicates both should be used but various discussions (see links below) suggest

you can use the ContentTypeRef to create a list with a content type, or you can use a ContentTypeBinding to add it later.

I personally found this discussion somewhat hard to follow and Andrew's post just says DO IT without any additional explanation; this post documents my own findings around the why.

While I always use ContentTypeRef in my Schema.xml files because my custom lists are backed by a custom content type, I hadn't come across ContentTypeBinding in a list context until recently—or if I had, I assumed it was unnecessary since everything just works without it. My understanding of content types leads me to believe each list has its own internal content type or at the very least, its own set of fields (the latter is certainly evident in the duplication of fields in Schema.xml and the file used to provision custom fields).

All's well, or so I thought until I had to programmatically enumerate a list item's fields: I noticed my custom fields were listed twice. Creating a new list from the Custom List template and assigning my custom content type did not result in this duplication so I knew something was up with my custom list definition. For some reason, the problem was not evident when inspected using my best friend SharePoint Manager 2007.

As expected, removing the fields included in Schema.xml that are duplicated in my custom content type/fields broke the list.

It seems telling Schema.xml about my custom content type in the ContentTypeRef doesn't cut it—the ContentTypeBinding element is required to effectively map the list fields against the fields referenced in the content type. After adding a ContentTypeBinding element and enumerating a new list instance, the duplicates are gone.

Like Andrew illustrates, I add the ContentTypeBinding element to my ListDefinition.xml file between the ListTemplate and ListInstance elements (your file may be named differently):

<ContentTypeBinding ContentTypeId="0x0100CB568E1363E18245810A4EF25B057CCE" ListUrl="Lists/MyList" />

All's well once again... until next time!

Ps. Andy Burns asks himself:

I wonder what happens if you try to create a list definition without a content type reference?

Andy, you can’t leave me hanging like that man!!! I dropped the ContentTypeRef element from my Schema.xml file and while no errors were reported and a list instance only reported using the custom content type specified in ContentTypeBinding, NewForm.aspx was a dog’s breakfast with some aspects of the content type ignored. For example, I’ll often hide the Title field in my list definitions and yet there it was (sure, ShowInNewForm/ShowInEditForm might address this but that’s not the point). Fields also weren’t ordered the way they were in the content type definition.

Links

Thursday, 5 November 2009

Sorting and filtering doesn't work on custom HTML list field

After deploying a custom list today I noticed, much to my annoyance, list items were not respecting the OrderBy FieldRef specified in my view and sorting the list manually in either direction on the field in question had no effect. Worse, the Show Filter Choices menu item led to the display of a #Render Failed error message in the central pane and the Application event log and SharePoint logs reported the following:

Unknown SQL Exception 306 occured. Additional error information from SQL Server is included below.  The text, ntext, and image data types cannot be compared or sorted, except when using IS NULL or LIKE operator.  The ntext data type cannot be selected as DISTINCT because it is not comparable.

The #Render Failed issue seems to be a fairly well-known bug and was apparently been fixed in the June 2009 WSS Cumulative Update although it's unclear whether that problem is related to my general sort/filter problem.

The problem field did have an edit control block attached in my case and while I expected that to be the culprit, changing the field type from HTML to text resolved the problem for me. Not my preferred approach but acceptable in this particular case.

Wednesday, 4 November 2009

ListTemplate Name attribute doesn't resolve $Resources

Further to my previous 0x81070215 post, I've since discovered this error code also crops up when specifying an invalid ListTemplate value for the Name attribute.

In my case I was attempting to supply the value from a .resx file something like Name="$Resources:List_Name;". While resources are successfully resolved on other ListTemplate and List attributes, this doesn't seem to be the case with Name and its value must be specified explicitly; incidentally, the Name must match the name of the folder containing the list definition. The OOB 12-hive examples I've cross-checked also specify a literal value.

While this error code was presented in the UI, the SharePoint log files revealed how SharePoint was parsing the attribute value:

Cannot open "schema.xml": no such file or folder.
Failed to retrieve the list schema for feature {1B3FC94C-2FC6-4528-B968-4E91843C2005}, list template 13133; expected to find it at: "C:\Program Files\Common Files\Microsoft Shared\Web Server Extensions\12\Template\Features\TeMCorporateBannerListFeature\$Resources:List_Name;".
Unknown SPRequest error occurred. More information: 0x81070215

No biggie since DisplayName does handle resources for localisation however in this case I'm attempting to use resource files for consistency and to simplify maintenance across my list definition.

For reference, 0x81070201 seems to mean about the same thing (a similar error message I received after reverting the Name value to a literal with a typo).

Friday, 30 October 2009

Control template "ListForm" does not exist

I have no idea how I caused ListForm not to exist but after some clumsy tinkering with a custom schema.xml file, the main section of NewForm.aspx page was coming up blank and the AllItems.aspx page for all lists in all sites across my dev farm refused to render the normal menu.

The SharePoint log file was telling me:

Control template "ListForm" does not exist

Examining a list’s NewForm.aspx file in SharePoint Designer (which of course makes me feel dirty all over) you’ll note it holds a ListFormWebpart. “Control template” would further point me to the _controltemplates virtual directory—mapped to \12\TEMPLATE\CONTROLTEMPLATES, but this directory doesn’t contain a ListForm.ascx or ListFormWebpart.ascx file.

Thankfully the Application event log entry was more precise:

Load control template file /_controltemplates/DefaultTemplates.ascx failed: The file '/_controltemplates/DefaultTemplates.ascx' does not exist.

A quick check of \12\TEMPLATE\CONTROLTEMPLATES and of course DefaultTemplates.ascx was nowhere to be found. Copy/paste from a functional server and we’re back in business. Now to figure how what caused it to be deleted in the first place…

Sunday, 16 August 2009

Invalid data has been used to update the list item. The field you are trying to update may be read only.

Apparently, in my specific case today, this error message actually meant the equivalent of a runtime type mismatch.

In the context of a list event receiver, I was attempting to update one of the list item’s properties. AfterProperties is an SPItemEventDataCollection, which seems to really be a collection of strings. In trying to cram a Guid in there, I forgot to call ToString () or Convert.ToString (); the compiler didn’t complain but at runtime my friendly Guid was jailed in the bowels of SharePoint’s exception handlers. SharePoint simply returned

Invalid data has been used to update the list item. The field you are trying to update may be read only.

with nothing but a menacing smile on its horrible, scarred face.

Sunday, 9 August 2009

Event receiver doesn’t fire

It’s been a long, busy weekend and the brain’s gone to mush—so I’m making silly mistakes.

Starting with an existing, functional SPItemEventReceiver attached to a content type, I needed to add an extra event handler. I had ItemAdding and ItemUpdating wired up and debuggable but wanted to add a new ItemAdded handler.

On my first attempt, I simply added the extra handler method to my existing class derived from SPItemEventReceiver. When that didn’t work, I recalled originally wiring the individual handler methods within the content type definition so I added an extra Receiver element.

I realised my mistake when it dawned on me I was testing my changes against an existing list instance: having been provisioned using the original content type definition with only the ItemAdding and ItemUpdating event handlers, SharePoint will never update that instance retroactively without some custom code.

After creating a new list from the modified template, all three event handlers fire correctly.

Retrieving a list item’s attachments

As you might expect, accessing a list item’s attachments in SharePoint isn’t straightforward. While SPListItem.Attachments returns a string-based list of attachment names, you’ll probably need to translate that into a URL at the very least, if not manipulate the attachment itself.

It helps to understand where SharePoint stores attachments after they’re uploaded. As usual, SharePoint Manager 2007 provides some insight:List Item Attachments Location

Notice in the screenshot, I’m inspecting a list named “Announcements” and that list has one item (Hello Attachment—highlighted at the bottom). You’ll also notice there’s an Attachments folder sitting among the list items and it’s been expanded with to reveal another folder with the odd name of 2; below that you can actually see the attachment itself (My First Attachment.txt).

Before I get any further, I’ll point out the magical “2” folder isn’t magical at all: it relates to the list item in this list with the Id of 2—in this case, the Hello Attachment item (the first item in the list was deleted but, if it had attachments, there would be a corresponding “1” folder). It’s sensible to assume this structure exists to accommodate multiple attachments.

If you were to now try to access the Attachments folder in code using SPListItem.Folder, you’d be faced with a null reference exception. Instead, you need to ignore what SPM tells you about getting to the Attachments folder and arrive there instead using the parent list’s RootFolder property.

Assume you’re working within the scope of a foreach or have retrieved a list item via some other means:

SPList announcements = …Lists [“Announcements”]

foreach (SPListItem currentItem in announcements)
{
// we’re here
}

Before you do anything else, you’ll probably want to muck around and ensure you can actually access a list of attachments in some form. To identify the attachments by name, SPListItem.Attachment (SPAttachmentCollection) will return a collection of strings:

foreach (string currentAttachmentUrl in currentItem.Attachments)
{
}

At this point you’ve retrieved, from the example discussed earlier, a string like “My First Attachment.txt—not of much use on its own. As mentioned, you’re probably after the full URL at the very least.

To access the actual attachment and not just it’s name, retrieve the list item’s parent list (SPListItem.ParentList) and then the parent list’s RootFolder. From there you can use the SubFolders collection to retrieve the “Attachments” SPFolder. Beware the SubFolders indexer expects the URL of the folder, not its name.

Finally, you need to retrieve the numbered folder specific to the list item. Here’s the complete mess:

SPFolder attachments = currentItem.ParentList.RootFolder.SubFolders ["Attachments"].SubFolders [currentItem.ID.ToString ()]

The SPFolder object’s URL property can now be prefixed to the attachment’s name retrieved previously or you can enumerate the SPFiles within the SPFolder.

Back in the day, Eric Shupps posted a way to do this by walking down the structure from the Lists folder. I think the above code is a slight improvement since the code’s a bit more manageable and you don’t need to retrieve the Lists folder or the parent list by name.

Ps. RootFolder is actually quite interesting as its Name property is actually the internal name of parent SPList object.

 

Friday, 31 July 2009

Storing SharePoint List meta data

When I recently wanted to store some information about a list (i.e., meta data) I couldn’t find an obvious way using just SPList. SPList does expose the PropertiesXml property but doesn’t expose a setter. What I wanted was a property bag or hashtable of key/value pairs. I’ve seen suggestions to add an extra column for this purpose but that could lead to redundant data, extra maintenance, and wasted space and essentially becomes meta data about the list items. In my opinion, columns define the structure of the data and aren’t meta data (but feel free to debate that among yourselves!).

Alex Angas was kind enough to provide an answer to a question I posted on StackOverflow on this subject. His solution was to make use of the Properties hashtable hanging off the list’s RootFolder object (SPFolder) and here’s my code to do just that:

// Set the custom property
SPList myList = myWeb.Lists [“MyList”];

myList.RootFolder.Properties [“MyKey”] = “MyValue”;
myList.RootFolder.Update ();

// Retrieve the custom property
myList = myWeb.Lists [“MyList”];

string myValue = myList.RootFolder.Properties [“MyKey”] as string;

Nice. It’s worth pointing out that using SharePoint Manager 2007 the RootFolder can be found within the site collection root; expand the RootFolder node to locate the folder named after the list in question.

SPFolder RootFolder Properties

Update: Although RootFolder.Properties is a System.Collections.Hashtable, you’ll likely receive a SPInvalidPropertyException if you attempt to use anything other than a string, int, or DateTime. The debugger told me so ;-)

In answer to the same question Paul-Jan also suggested using a separate, hidden list to track meta data about a parent list (or lists, I suppose). I quite like this idea as a centralised “list meta list” and it could be as simple as three column list to identify a list by ID and store a key/value pair. On the other hand, I prefer keeping stuff like meta data with the object in question so my preference would be SPList.Properties; the RootFolder solution seems like a passable alternative.