Exception filters

If you want to handle exceptions in a generic way using a filter, there is a class called ExceptionFilterAttribute. It derives from the ActionFilterAttribute, and provides the OnCommandExceptionAsync method, which is a common place where you can log or handle any exceptions.

The OnCommandExceptionAsync is called whenever an error occurs in a method triggered by a command or a static command.

The ActionFilterAttribute class then defines the OnPageExceptionAsync and OnPresenterExceptionAsync methods. These methods are called when any other exception occurs when the page or presenter is being processed. In most cases, it catches the exceptions in the Init, Load and PreRender in the viewmodel, and the exceptions that occur during the rendering or serialization phases.

using System;
using System.Collections.Generic;
using System.Linq;
using System.Threading.Tasks;
using DotVVM.Framework.Hosting;
using DotVVM.Framework.Runtime.Filters;

namespace DotvvmDemo
{
    public class ErrorLoggingActionFilter : ExceptionFilterAttribute
    {
        protected override Task OnCommandExceptionAsync(IDotvvmRequestContext context, ActionInfo actionInfo, Exception exception)
        {
            // Log exceptions from commands in the viewmodel
			LogService.LogException(exception.ToString());

            return base.OnCommandExceptionAsync(context, actionInfo, exception);
        }
        
        protected override Task OnPageExceptionAsync(IDotvvmRequestContext context, Exception exception)
        {
            // Log other exceptions that occur during the page execution
			LogService.LogException(exception.ToString());

            return base.OnPageExceptionAsync(context, exception);
        } 

        protected override Task OnPresenterExceptionAsync(IDotvvmRequestContext context, Exception exception)
        {
            // Log other exceptions that occur during the page or custom presenter execution
			LogService.LogException(exception.ToString());

            return base.OnPresenterExceptionAsync(context, exception);
        }               
    }
}

Handle exceptions from all commands

In many apps, the commands sometimes end with an exception. However, you don't always want to show the error page to the user. You want to log the exception and display some friendly error message to the user.

In such cases you can use something like this:

using System;
using System.Collections.Generic;
using System.Linq;
using System.Threading.Tasks;
using DotVVM.Framework.Hosting;
using DotVVM.Framework.Runtime.Filters;

namespace DotvvmDemo
{
    public class ErrorHandlingActionFilter : ExceptionFilterAttribute
    {
        protected override Task OnCommandExceptionAsync(IDotvvmRequestContext context, ActionInfo actionInfo, Exception exception)
        {
			// AppViewModelBase declares the ErrorMessage property to display error messages
			// If it is set, the master page will display the error message alert.
            if (context.ViewModel is AppViewModelBase)
            {
				((AppViewModelBase) context.ViewModel).ErrorMessage = exception.Message;
                
				// We need the request to end normally, not with an error
                context.IsCommandExceptionHandled = true;
            }

            return base.OnCommandExceptionAsync(context, actionInfo, exception);
        }       
    }
}

The AppViewModelBase is a base class for all viewmodels in the application and has the ErrorMessage property. If the request execution should continue like there was no error, we need to set context.IsCommandExceptionHandled to true.

Create a custom error page

If the exception occurs during the Init, Load and PreRender phase, you often need to redirect the user to an error page.

You can do it in the OnPageExceptionAsync method like this:

using System;
using System.Collections.Generic;
using System.Linq;
using System.Threading.Tasks;
using DotVVM.Framework.Hosting;
using DotVVM.Framework.Runtime.Filters;

namespace DotvvmDemo
{
    public class ErrorHandlingActionFilter : ExceptionFilterAttribute
    {
        protected override Task OnPageExceptionAsync(IDotvvmRequestContext context, Exception exception)
        {
            // Suppress the default DotVVM error page
			context.IsPageExceptionHandled = true;
            
            // TODO: Log the exception details
            
            // Redirect to the /error500 page 
            context.RedirectToUrl("/error500");

            return base.OnPageExceptionAsync(context, exception);
        }       
    }
}

See also