Having worked with the developer nightmare that is Microsoft SharePoint for a couple of years and being one of the architects of a framework which sits on top of it, I’ve come to know a lot about various parts of it. SharePoint is notorious for being awful to work with, and much of the effort which has gone into our framework has been around making it easier, faster and less painful to use. Rather than an all out rant, I thought I’d post about some of the shadier parts of SharePoint, with war stories interspersed for… posterity? Comedy? I don’t know…
Let’s start off with my favourite one! IsPublishingWeb() seems like an honest enough method right? You call it on an SPWeb to figure out if it is a publishing web or not. Simple! And it always works… except for when it doesn’t. Turns out that it sometimes returns the wrong result and it’s non-deterministic about the whole shebang.
We tend to provision site collections using object model code in a feature activation event-receiver. About a year ago, a colleague and I spent a couple of days trying to figure out why our provisioning code was failing in one particular environment, but worked everywhere else. We tried everything, thinking it was something complex like a fundamental flaw in our deployment scripts or an issue related to SP multi-tenanted environments. Nope, it was simply some overly defensive code which called this method as a sanity check – unnecessary since we actually knew we were dealing with a publishing web, but understandable nonetheless. Having gone completely around the twist, we whipped up a console app which would create publishing webs and call this method afterwards, and we executed two instances of it simultaneously against our, until then, untainted environment. We observed that under concurrent site creation, this bug chooses to rear its ugly head. I think this was the point when I lost what little faith I had in the SP object model.
Linq to SharePoint
Linq to SharePoint is Microsoft’s attempt at providing a more modern way of querying SP resources without paying the performance penalty of the object model, and without resorting to CAML. Seems like a good idea, right? In the past, many of our SP sites made use of this technology for reading data from lists in a very simple manner and it worked fine for the most part. But sporadically, and usually once every month or two, these reads would mysteriously begin to fail with a horrible stack trace and it could only be resolved by recycling app pools. For the longest time, Microsoft ignored our complaints blaming our setup and code, despite the fact that it has been observed by other people too. We simply ended up replacing all L2SP code with object model code – problem solved! Avoid like the plague.
Custom Field Types
I’ve recently gone through the ordeal of implementing a custom SP field type. If you’ve ever done the same, and you’ve tried to add properties to it, you will also have tried to make use of SPField.GetCustomProperty() and SetCustomProperty(). You will also have realised that the bloody methods don’t work!!! There’s a variety of workarounds, some of which involve doing crazy stuff like storing property values temporarily in thread local storage. Needless to say, one should not have to do this!!! It really is quite amazing that M$ developers manage to botch something as simple as storing key/value data against an object, but I suppose incompetency knows no bounds.
Web Provisioned Event Receiver
We make heavy use of event-receivers to initialise SPWebs after creation. There’s a funny bug where a WebProvisioned event-receiver will be called twice if you create the web through object model code, but once if you create it through the UI. Obviously the desirable behaviour is generally to execute it once, and this can be achieved by setting SPWebEventProperties.Cancel to true.
SPWeb AllProperties vs Properties
You can store key/value data against an SPWeb in two ways- via the AllProperties hash table or via the Properties SPPropertyBag. Now for some godawful reason, SPPropertyBag internally lowercaseifies the key you use. Microsoft has declared Properties to be a legacy thing, presumably because of the above weirdness and maybe because of other things too? Unfortunately, when they introduced AllProperties, they also introduced some funny interactions between the two, leading to some bizarre behaviour which is exhibited depending on whether your keys are lower case and on the order in which you update SPWeb and SPWeb.Properties. Someone has blogged about it in detail here.
The SharePoint CssRegistration control allows you to render CSS links. I originally used it as it exposes an After property which purportedly allows you to specify that one .css file should be included after another – a common use case is to include your own CSS after corev4.css. IIRC, this works fine for two CSS files but fails for more. In fact, when using this property to impose ordering on >2 CSS links, the result seems completely arbitrary! If it was at least deterministically wrong, then it would be correctable!
Array prototype extension
I’ve blogged about the horrors within previously.
Yup, MSDN is a disaster. Documentation on the SharePoint object model is at best scant and vague, and quite often it’s completely incorrect and full of lies. Let’s have a look at the docs for a fundamental method, SPWeb.GetList(string strUrl):
According to Visual Studio => strUrl: A string that contains the site-relative URL for a list, for example, /Lists/Announcements.
According to MSDN => strUrl: The server-relative URL to the root folder of a list, such as /sites/sitecollection/subsite/Lists/Announcements.
Problems here! Firstly, the VS and MSDN docs contradict each other. Secondly, the VS example of a site-relative URL is incorrect – M$ convention is that they do not begin with forward slashes. Thirdly, both are wrong. I’ve written unit-tests against the SP object model which tell me that GetList() works with (at least) server-relative URLs and absolute URLs. This is merely one example- MSDN is rife with this rubbish… is it any surprise that most SP devs resort to a decompiler and skip the docs altogether?