Search code examples
asp.netdotvvm

DotVVM implementing Toastr.js


I want to implement toastr.js in dotvvm. I created an exception filter which catch all the exception errors on the viewmodel:

public class ErrorLoggingActionFilter : ExceptionFilterAttribute
    {

        protected override async Task OnPageExceptionAsync(IDotvvmRequestContext context, Exception exception)
        {

            //context.CustomResponseProperties.Add("Error", exception.Message);

            // Inject JavaScript code to display toastr notification
            // Get the exception message
            string errorMessage = exception.Message;
            // Inject JavaScript code to display toastr notification
            string toastrScript = $"<script>toastr.error('{errorMessage}');</script>";
            context.ResourceManager.AddInlineScript(toastrScript);

            // Mark the exception as handled
            context.IsPageExceptionHandled = true;

            await base.OnPageExceptionAsync(context, exception);
        }


    }

but i'm having hard time adding the toastr.js and implementing it.


Solution

  • You should use OnCommandExceptionAsync instead of OnPageExceptionAsync.

    • The "command exception" is an exception that occurs during a command or a static command - the page is already loaded in the browser, the user has done something, and it produced an error. In such situation, it makes sense to display a toastr notification on the page the user is currently seeing.
    • The "page exception" means there was a problem loading or rendering the page. If such exception occurs, the toastr wouldn't help the user anyway because the page cannot be loaded at all.

    Additionally, the AddInlineScript requires just the JS code without the <script></script> tags:

    public class ErrorLoggingActionFilter : ExceptionFilterAttribute
    {
        protected override Task OnCommandExceptionAsync(IDotvvmRequestContext context, ActionInfo actionInfo, Exception ex)
        {
            string errorMessage = KnockoutHelper.MakeStringLiteral(ex.Message);
            string toastrScript = $"toastr.error('{errorMessage}');";
            context.ResourceManager.AddInlineScript(toastrScript);
    
            context.IsCommandExceptionHandled = true;
    
            return base.OnCommandExceptionAsync(context, actionInfo, ex);
        }   
    }
    

    Also, be careful when building scripts using the string concatenation. If the error message contains apostrophe, it would end the string literal and interpret the rest as a script code. If an attacker finds a way how to inject their input into the error message, you would make a script injection vulnerability in your app.

    I've added KnockoutHelper.MakeStringLiteral to escape characters in the error message.

    Finally, don't forget to register all script and style dependencies in DotvvmStartup:

    config.Resources.RegisterScriptFile("jquery", "wwwroot/jquery/jquery.min.js");
    config.Resources.RegisterScriptFile("toastr", "wwwroot/toastr.js/toastr.min.js", dependencies: new [] { "jquery", "toastr-css" });
    config.Resources.RegisterStylesheetFile("toastr-css", "wwwroot/toastr.js/toastr.min.css");