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.

Saturday 25 July 2009

Content Type ID Structure

Creating a custom content type in a feature requires you specify the ID attribute.

Content type IDs are constructed hierarchically and you can trace the lineage of a content type through its ID. A custom content type will often derive from the Item content type—the most basic content type you can use. Item is derived from the System content type and contains the ever-present Title field (Title can be hidden if necessary). Note the System content type is sealed, meaning it can’t be derived from in your code.

The ID of the System content type is 0x and the Item content type appends 01, giving you 0x01. A separator must be used between all subsequent IDs appended to the base string; 00 is used for that purpose, giving you 0x0100.

A custom content type will need its own ID appended to the base system-item-separator ID and the best way to do that is using a GUID without the braces and hyphens (use guidgen.exe, included with Visual Studio).

Here’s an example with the base system-item-separator ID combination bolded for clarity:

0x0100C1FA419A4F94429C8F40DB576B211FD7

To create additional custom content types derived from an existing custom content type, add an addition separator and GUID:

0x0100C1FA419A4F94429C8F40DB576B211FD700B87CFA11-7687-4171-B67B-E1DFE20BBB86

Content type IDs are limited in length to 1024 characters so if you’re running out of room or just don’t like using GUIDs, a content type ID can optionally be specified with two digits other than 00. WSS uses this convention so be wary of any clashes with your own custom content types.

If you’re working with pages, note the Page content type derives from System Page content type, which in turn derives from Document which in turn derives from Item. The Page content type ID is therefore

0x010100C568DB52D9D0A14D9B2FDCC96666E9F2007948130EC3DB064584E219954237AF39

Additional Resources:

http://msdn.microsoft.com/en-us/library/aa543822.aspx

Tuesday 21 July 2009

DHCP-assigned IP address and DNS host name clash - duh

Mental note #1: if using host headers with MOSS (or IIS) ensure the web server is configured with a static IP address or the NIC’s MAC address is reserved within DHCP.

Mental note #2: Just because it’s SharePoint, don’t forget the easy things! No, really!!!

I came across an unusual problem today after a MOSS server was imaged and restored to a new physical blade: Central Admin, the default SSP web app, and a specially-created sanity check web app were all working beautifully but the single site configured with a host header refused to load.

In addition, the Application event log was full of errors suggesting a database server connectivity issue:

The start address http://site.com cannot be crawled. The item could not be crawled because the crawler could not connect to the repository.

The database connection wasn’t the problem but nevertheless, SharePoint couldn’t find what it was looking for. The WFE’s NIC changed as part of the migration, which meant a new MAC address, and therefore a new DHCP lease for a different IP address that DNS knew nothing about.

Friday 17 July 2009

PDF iFilter not indexing content

Don’t forget: installing and configuring an iFilter to allow SharePoint to search PDF documents won’t index graphical PDF content. In other words, if search is returning PDF results based on title or other meta data but not PDF content, double-check whether that content can be highlighted and copied to notepad as text—and watch out for scanned documents!!!

Conditional Post-Build Event Command for x64 sgen

I’ve bitten the bullet and decided to run Windows Server 2008 Hyper-V on my workstation; in addition to virtualising my MOSS dev environment, I’ve also chosen to virtualise my workstation environment on Windows Server 2008 x64; work won’t let me get away with Windows 7 RC1 and there’s no “supported” upgrade path to the RTM anyway.

You may have read my previous post on the subject of x64 targeting with Visual Studio setup projects; today, however, is all about just getting VS to compile a project with a post-build event where Visual Studio 2008 is running on Windows Server 2008 x64 with SP2. In our case, the post-build event needs to run sgen.exe from the correct location since some of our devs are still on Vista x32. And yeah, I know, post-build events are old school but it’s an existing solution…

Windows Server 2008 with Visual Studio 2008 SP1 and .NET 3.5 SP1 installed does not include sgen.exe for some reason. Why not?!? Good question—you can install it by downloading the Windows SDK for Windows Server 2008 and .NET Framework 3.5. v6.0a does seem to be installed by VS2008 on 32-bit/W2k3 environments (more about this). Kicking off the SDK installer, I chose to install the .NET Development Tools only (Developer Tools\Windows Development Tools\.NET Development Tools).

This all seems good but sgen will be installed to a different location than you may be used to: %programfiles%\Microsoft SDKs\Windows\v6.1\Bin\x64 (the 64-bit Program Files folder, that is). To accommodate this difference from the 32-bit world, I need some conditional logic in my post-build event.

At first glance, using the %processor_architecture% environment variable makes sense—it returns “x86” in my current XP 32-bit environment, presumably the same in Vista x32, and “AMD64” in Hyper-V… not quite “x64” but enough to branch on. As we all know, however, Visual Studio is only available as a 32-bit application and seems to do some additional environment variable setting of is own: echo %processor_architecture% in a post-build event prints out “x86”, obviously the same as our 32-bit environment. No good.

To work around and take advantage of this, my post-build event compares the %ProgramFiles% variable against “C:\Program Files”; when queried from a post-build event in a 64-bit environment, it reliably returns “C:\Program Files (x86)” which I know is the 32-bit Program Files folder; in that case, my script uses the 64-bit sgen. Note the same variable will return “C:\Program Files” in a normal command window so be careful and test in VS directly.

In the end, here is my post-build event:

REM Use the 64-bit sgen from the Win 2008 and .NET 3.5 SDK in a 64-bit dev environment
REM ProgramFiles variable is set to 'Program Files (x86)’ in a x64 environment
REM Processor_Architecture variable returns x86 in both an x86 and x64 environment within VS

if /I "%ProgramFiles%" == "C:\Program Files" (
set ToolPath="C:\Program Files\Microsoft
SDKs\Windows\v6.0A\Bin\sgen.exe"
) else (
set ToolPath="C:\Program Files\Microsoft
SDKs\Windows\v6.1\Bin\x64\sgen.exe"
)

%ToolPath% /compiler:"\"/keyfile:$(ProjectDir)
MyKeyFile.snk"\" /force "$(TargetPath)"

Thursday 9 July 2009

Joel Oleson at the Perth SharePoint User Group

After a great showing from Greg Low last month, the Perth SharePoint User Group boys have pulled SharePoint superstar Joel Oleson on his way home from the NZ Community SharePoint Conference 2009.

Joel’s presentation is “Preparing for Upgrade to SharePoint 2010.” Here’s some pre-reading: http://www.sharepointjoel.com/Lists/Posts/Post.aspx?ID=238

This promises to be the local SharePoint event of the year so get your RSVP into SharePoint Sezai via the user group web site if you haven’t already and block out 12:30pm in your calendar!

Wednesday 8 July 2009

YSlow for Firefox 3.5 Lives?

YSlow has been the tool for measuring page payload and providing the metrics you need to optimise web site performance beyond the web server. Shock horror when I recently upgraded Firefox to version 3.5 and couldn’t install YSlow.

Initial rumours confirmed the current version of YSlow doesn’t work with FF3.5 but also suggested development by Yahoo! had ceased. Meanwhile Google launched Page Speed—a likeable YSlow competitor (maybe?).

A recent posting from a Yahoo! dev would suggest YSlow will actually be updated but “the team has run into some integration issues with firebug 1.4.” If you want to install FF 3.x and 3.5 side-by-side, check out this guy’s article.

Monday 6 July 2009

New Sites, New Widgets

Rottnest Island Authority Re-launch

The second-last site to be launched Home - Rottnest Islandon Tourism WA's fully branded, MOSS-based site provisioning platform went live last Thursday; I reckon it’s one of the best looking sites they've launched to date (the Rottnest Island photography helps, of course). Check it out: http://www.rottnestisland.com

[Update 22 July: As mentioned in my profile to the right, I'd like to clarify the fact the new rottnestisland.com web site is provided by Tourism Western Australia under the Tourism eMarketplace program; although I was involved in the technical construction of the web site as a contractor working for Tourism Western Australia, Mediawhole and mediawhole.com were NOT involved in the launch of this web site. Whereas I previously used the terms "we" and "our" in this post, I was referring to Tourism WA and teams working with the Rottnest Island Authority.]

Booking Exchange

On the subject of all things new, the new online booking capability has also launched on westernaustralia.com. The system integrates with our existing search function and provides live availability information from V3’s Open Booking Exchange. The politics around this apparently simple change were massive but the technology side was relatively straightforward by comparison (web service calls from within SQL Server are as complex as this got from our end). If you’re a tourism operator, find out more.

Travel Planner

WACOM Travel Planner

The online travel planner was also finally launched after nearly a year of work with a Sydney-based agency. Luke was our man on the ground with this one and he did a great job integrating drop after drop of this widget.

The travel planner “helps visitors collect, organise and share their WA travel itineraries.” You can sign up from the westernaustralia.com homepage and add items from across the site to your travel wallet.