Handling an orphaned SPPersistedObject when working with e.g. SPJobDefinition or SPDiagnosticsServiceBase
I've been working with improving our Puzzlepart Framework components for simplifying development of SharePoint Timer Jobs lately, in relation to our upcoming release of "Did - The calendar is the timesheet" business app for SharePoint, and (as usual when digging deep into SharePoint) I ran into some problems with our beloved platform that needed resolution:-)
If you're about to work with any type of SPPersistedObject I recommend you to first read through Charlie Hollands "The skinny on SPPersistedObject and the Hierarchical Object Store in SharePoint 2010" to make sure you've got the basics right.
Creating SPPersistedObjects usually happens when you call Update() on something like your SPJobDefinition subclass. In the case of a custom logger, the creation happens indirectly through the call to SPDiagnosticsServiceBase.GetLocal<T>() (which fails if the object is already there). This is all well and good, until you decide to rename or move your class, and redeploy your solution. The only way do delete an SPPersistedObject is to call Delete() on the object and the only way to get a SPPersistedObject is to call GetChild<T>(name). Thus if your typeof(T) is not loadable in the current context you cannot get the object and thus cannot delete it.
Usually this will only create orphans in your config db that will spam your ULS logs with typeload errors, but sometimes it also blocks your new or updated type from working properly. In our case we were experimenting with ILMerge and (temporarily) had the same class defined in multiple assemblies in our environment which totally confused SharePoint. It seems as the object-exists logic for SPPersistedObjects uses only the typename, while the creation logic pulls the AssemblyQualifiedName from the configdb, making the orphaned object registration a blocker for the new one.
The supported (totally undocumented solution)
After blogging this my colleague KjellSJ brought to my attention the undocumented deleteconfigurationobject stsadm command. SharePoint blogging legend Bil Simser wrote about this a loong time ago, and he'll help you avoid my SQL nastyness below:-)
The (totally unsupported) solution
I could obviously revert my svn trunk and try to rebuild and deploy my old component-setup in order to allow loading of the orphan, but that seemed just too painful in a dev-environment. Que SQL:
SELECT [Id], [ClassId], [ParentId],[Name],[Status],[Version],[Properties]
WHERE ClassId in
WHERE FullName like 'Pzl.Framework%')
Obviously replace your typename in the last statement. This will allow you to see the object registrations and I'll let you figure out the delete statement for those yourself:-) When the invalid object registrations are gone, you can take care of the entries in the Classes table. Totally unsupported but helpful for your dev environment when you don't want to recreate your WebApplication or farm.