It’s 4:59PM Friday afternoon and your long work week is almost over; one minute away from 48 hours of non-stop, fun-filled, Mountain Dew fueled LARPing. Just as you stand up to leave, your work phone rings and it’s your favorite client. Going against your better judgement you decide to be nice and answer.
“Help Hasagn Sailorslayer! Thoust Dragon Smaug breathed fire on our site and tis no more!”… the client says while speaking with a horrible British accent. “I swear, all I did was a publish and now the entire site is erroring!”.
The client provides you with all the vague, helpless information you’ve come to expect and now your weekend of throwing lightning bolts may be delayed.
After a half hour and a couple hundred “WTFs” you remember Sitecore troubleshooting basics. You check the logs and find an object reference error on the “Main Navigation”; somehow the client deleted the Main Navigation’s datasource item while ignoring common sense and Sitecore’s warnings. You restore the deleted item and the crisis has been adverted, the client is happy and you begin to rethink the client’s request of needing full admin privileges.
There are a lot of ways we could prevent this error from happening. First we can deny delete permissions, set the item to protected, add try/catches, null checks and you can even place something like this on every view:
Even though I have Experience Editor specific views enabled, the code in the image above is an ugly and tedious approach. I am going to provide you with a more elegant solution to prevent datasource errors by using some code and the mvc.getRenderer and mvc.renderRendering pipelines.
Note: I’ve left out some minor code, you can download the solution from GitHub.
I created AddDatasourceWrapper that inherits Sitecore.Mvc.ExperienceEditor.Pipelines.Response.RenderRendering.AddWrapper. You can read more on the AddWrapper here.
On line 25, I am checking to see if the rendering item requires a datasource. I am determining this by whether the “Datasource Template” field is populated. If it is populated, I then check to see if the rendering’s datasource item exists. If it does not, I return the DatasourceRenderingMarker that contains the error message along with the standard Experience Editor chrome.
The RenderingMarker contains the GetStart() and GetEnd() methods. GetStart() calls Placeholder.GetControlStartMarker, GetEnd() calls Placeholder.GetControlEndMarker and along with GetClientData, this is what wraps the view with that fancy Experience Editor chrome. You can also add custom markup here like I am on lines 21-25, but be sure to close all the HTML tags; the Experience Editor tends to hate broken HTML.
Note: You’ll need to merge this into your site’s CSS.
The custom markup along with the CSS produces the following stylized error message to inform the Content Author of the issue:
I am only concerned with two rendering types, Controller Renderings and View Renderings. If the rendering requires a datasource and that datasource is empty or contains a guid to a non-existent item, I set the view path to a blank view. I also want make sure to log this for troubleshooting purposes. I decided to split these log entries into separate log files so it’s easier to find.
Disclosure: I started this proof of concept on December 7th; I have not had the opportunity to fully integrate and test it on a real project. It has been tested Sitecore version 8.1 and 8.2. Apologies if I forgot something.
The source code can be found and DOWNLOADED(!) from GitHub.
Do you enjoy my oddly themed blogs and wish you had access to even more of me and my ideas? Good news, you’re in luck!
If 140 characters is your thing, follow me on Twitter.
If you hate reading and watching Sitecore videos entertains you, head over to my YouTube channel! Sometimes I entertain, sometime I provide useful Sitecore information and sometimes I can do both in the same video.
I can also be found hanging out on the Sitecore channels on Slack, I like it, although it occasionally triggers AOL chat room flashbacks from the olden days.
You can also find me adding content on LinkedIn and on Reddit.