I migrated a SharePoint sitecollection into my local SharePoint development environment. As source material I had a backup of the sitecollection’s content database, and a couple of assemblies to go into the local webapplication bin. Missing is the web.config, and also the knowledge whether or not there is a dependency on other assemblies: be it within the local bin or within the GAC. I restored the database backup within my local SQL installation, created a new SharePoint webapplication, and attached the restored db to it. This made the site locally available and browsable.
Runtime it then appeared that I am indeed still missing some of the site resources. Browsing of several pages results in the infamous message: “Web Part Error: A Web Part or Web Form Control on this Page cannot be displayed or imported. The type could not be found or it is not registered as safe.”
The trick is now to detect the type of the error-causing webpart(s). Then I can verify whether or not I have them in the assemblies, and if so add an SafeControl entry for it in the web.config. I tried to have a look at the inner content of the webpage by opening it in SharePoint designer. This also gives the error message. Then I tried to find out the typenames by putting the page in webpart maintenance mode. If you have the appropriate rights (given my local environment, I naturally do), you can easily enter this mode by attaching ‘?Contents=1’ to the page-url. This gave the strange effect that 3 out of 5 webparts are displayed as ‘ErrorWebPart’.
This looked to me a display issue within webpart maintenance. Therefore I went explicitly self at a deeper level by inspecting the webpart info via the SharePoint Object API. However, even then the error-causing webparts have runtime the type ‘Microsoft.SharePoint.WebPartPages.ErrorWebPart’:
Surfing around I found out that this is a known SharePoint behavior. Any webpart that has gone bad, appears runtime as ‘ErrorWebPart’ instead.
So I decided to take it to yet another deeper level, and get into directly at the SQL content db. I queried the WebParts table for retrieving information of the webparts on the specific page:
This gives the 5 entries for the contained webparts, but sadly not a readable description of their types. The displayed tp_WebPartTypeId is not a cross-reference to an entry in another table. This guid is actually a MD5 calculated hash of a string composed of <the fullname of webpart’s assembly> + ‘|’ + <full classname of webpart>. MD5 hashing is irreversible, so it is not possible to convert these guids back into a human-readable format. Apparently, SharePoint itself builds up runtime an in-memory administration of the calculated hash of all the allowed webparts in a sitecollection. When requesting a webpart page, SharePoint compares it’s tp_WebPartTypeId values against this administration to derive the concrete webpart type. In case a WebPartTypeId is not found, SharePoint reports this via the errormessage “Web Part Error: A Web Part or Web Form Control on this Page cannot be displayed or imported. The type could not be found or it is not registered as safe.” Because of the irreversibility of the MD5 algorithm, even SharePoint code itself cannot derive the typename of these error-causing webparts.
To my humble opinion, this really sucks! How are you ever able to determine the typename of an error-causing webpart in this approach? And for a best practice: document whatever non-SharePoint out-of-the-box webpart is used in your site, and document for each webpart the fullname (including version number!) of its assembly.
Fantastic write-up. I had just gotten to the web part maintenance page and was about to proceed as you did to the next step, which was looking in the database. Thank you for the detailed explanation of what you found, as it saved me from wasting my time in trying to go further when it's just not possible to do so.
ReplyDeleteI agree with your final technical assessment that the limitation on troubleshooting this particular issue "really sucks!"