This blog post explains how you can handle exceptions generated by all types of renderings in MVC solutions using the Sitecore ASP.NET web Content Management System (CMS).
For background information on this topic, see the blog post linked in the Resources section at the bottom of this page.
My initial thinking on this topic was to replace all of the processors in the mvc.renderRendering pipeline with a single processor that would add exception management logic around the invocation of a new pipeline that would contain all of those original processors. I am certain that solution is possible, but I decided to override only the ExecuteRenderer, as I am not sure that I want to handle exceptions in those other processors (InitializeProfiling, RenderFromCache, etc.). So you should still manage exceptions at a higher level.
Here is some code to override ExecuteRenderer:
SC = Sitecore;
TextWriter restoreWriter = args.Writer;
StringBuilder sb =
(StringWriter sw =
// nested try attempts to workaround defect in HtmlTextWriter
HtmlTextWriter hw =
args.Writer = hw;
"Rendering exception processing "
+ args.Rendering +
" for "
SC.Web.UI.WebControls.ErrorControl errorControl = SC.Configuration.Factory.CreateErrorControl(
" : "
// if you don't ensure proper exception handling at a higher level
// you may prefer to redirect here.
// SC.Globalization.Translate.Text("An error occurred."));
args.Writer = restoreWriter;
CustomErrorsMode mode = SC.Configuration.Settings.CustomErrorsMode;
mode == CustomErrorsMode.Off
.ShowExceptionsToAdministrators && SC.Context.User.IsAdministrator)
.ShowExceptionsInPageEditor && SC.Context.PageMode.IsPageEditor)
.ShowExceptionsInPreview && SC.Context.PageMode.IsPreview)
.ShowExceptionsInDebugger && SC.Context.PageMode.IsDebugging)
|| (mode == CustomErrorsMode.RemoteOnly && HttpContext.Current.Request.IsLocal);
Here is a Web.config include file (Sitecore.Sharedsource.Mvc.ExecuteRendering.config in my case) to enable this override of ExecuteRenderer:
Because an MVC layout is a view, and Sitecore uses the mvc.renderRendering pipeline to invoke all views, this solution handles exceptions in the layout view as well as all nested renderings. Unfortunately, the ErrorControl (intended for use within a page) does not generate <html> and <body> elements, but the browser still renders the error message correctly:
I think it might be possible to use this fact to enable caching of entire pages as opposed to individual renderings.
If you trap exceptions at more than one level, you should probably implement a class to encapsulate some of the logic I've replicated in multiple classes in these blog posts.
John, Great article as always. It's been a while since this bug in htmltextwriter was identified. I should imagine that Microsoft would have fixed this by now? Do you know if this has been identified as a Microsoft bug? - Lars
Hi Lars, Actually, I circulated variants of this code past numerous Sitecore staff before posting and could not get a definitive answer. While I expect Microsoft would have addressed the issue by now, one of the most technical people that responded to me said they couldn’t find any difference between .NET 2.0 and 4.0 (maybe it only affected 1.x?). Anyway I have a feeling that this issue may only affect sinks that are streams, not objects in memory (what’s the point of buffering data written to memory, and there doesn’t seem to be anything to dispose anyway). But I thought it might be best to call out the issue and be safe rather than potentially sorry. I hope to get a resolution and update the code in this and another post that uses a similar approach, but I am not sure how to get complete confirmation, especially as the issue is not specific to Sitecore. Thanks for reading, -John