How can I prevent blocks from bringing down an entire page in Episerver?

  • Page Owner: Not Set
  • Last Reviewed: 2020-04-03

I have several blocks that pull data from third parties that are not reliable. I don't want to wrap every single block in try catch blocks. How can I prevent these blocks from bringing down a page if an exception is thrown?


Answer

You can handle this with a custom HandleErrorAttribute attribute and by making all of your block controllers inherit from a common base.

First, the attribute:

    public class NonCriticalAttribute : HandleErrorAttribute
    {
        public override void OnException(ExceptionContext filterContext)
        {
            var logger = ServiceLocator.Current.GetInstance<ILogger>();
            logger.LogException(filterContext.Exception);

            string controllerName = (string)filterContext.RouteData.Values["controller"];
            string actionName = (string)filterContext.RouteData.Values["action"];
            HandleErrorInfo model = new HandleErrorInfo(filterContext.Exception, controllerName, actionName);
            filterContext.Result = new ViewResult
            {
                ViewName = View == "Error" ? "~/Views/Shared/Empty.cshtml" : View,
                MasterName = Master,
                ViewData = new ViewDataDictionary<HandleErrorInfo>(model),
                TempData = filterContext.Controller.TempData
            };
            filterContext.ExceptionHandled = true;
        }
    }

You will need to be sure you have an empty view at ~/Views/Shared/Empty.cshtml. You can adjust this path if needed. You could also put some kind of verbiage in the view (for example: "An error has occurred."), though it may look weird if several blocks threw errors, and since this covers all blocks, it may appear in some strange places.

This example also assumes you're using Blend's Sentry package.

Finally, you need to have a base block controller that all your block controllers (including the default one) inherit:

    [NonCritical]
    public abstract class BaseBlockController<T> : BlockController<T> where T : BlockData
    {
    }

When any block controller marked as [NonCritical] throws an exception, it is caught, logged, and an empty string is sent to the view, allowing the rest of the page to render.