Handle and Log Server-Side Errors in ASP.NET Core

  • 3 minutes to read

The ASP.NET Core Dashboard allows you to catch exceptions using a custom exception filter.

View Example: ASP.NET Core Dashboard - How to handle errors

Catch All Unhandled Exceptions

You can register a custom exception filter globally to catch all the unhandled exceptions. In this case, the exception filter catches unhandled exceptions from all the controllers and actions.

In your ASP.NET Core project, open Startup.cs file and create the CustomExceptionFilter class that implements the IExceptionFilter interface to use a custom filter:

```c#
using Microsoft.AspNetCore.Mvc.Filters;

//...

public class CustomExceptionFilter : IExceptionFilter {
    // ...
}
```

Configure an exception filter:

  • Define CustomExceptionFilter to save the actual exception and information about the issue’s cause into a text file.
  • You can use the built-in ASP.NET Core logger to log errors.
using Microsoft.AspNetCore.Mvc.Filters;
using Microsoft.AspNetCore.Hosting;
using System.IO;
using System.Text;
using DevExpress.DashboardCommon;

// ...

public class CustomExceptionFilter : IExceptionFilter {
    IHostingEnvironment Env;
    public CustomExceptionFilter(IHostingEnvironment hostingEnvironment) {
        Env = hostingEnvironment;
    }

    public void OnException(ExceptionContext context) {
        AddToLog(context.Exception, Path.Combine(Env.ContentRootPath, "App_Data", "Error.log"));
    }

    public static void AddToLog(Exception exception, string path) {
        StringBuilder sb = new StringBuilder();
        sb.AppendLine(DateTime.Now.ToLocalTime().ToString("F"));
        GetExceptionInfo(exception, sb);
        sb.AppendLine("------------------------------------------------------------" + Environment.NewLine);
        File.AppendAllText(path, sb.ToString());
    }

    private static void GetExceptionInfo(Exception exception, StringBuilder sb) {
        sb.AppendLine(exception.GetType().ToString());
        sb.AppendLine(exception.Message);
        sb.AppendLine("Stack Trace: ");
        sb.AppendLine(exception.StackTrace);
        if (exception is DashboardDataLoadingException) {
            foreach (var dataLoadingError in ((DashboardDataLoadingException)exception).Errors) {
                sb.AppendLine("InnerException: ");
                GetExceptionInfo(dataLoadingError.InnerException, sb);
            }
        }
        if (exception.InnerException != null) {
            sb.AppendLine("InnerException: ");
            GetExceptionInfo(exception.InnerException, sb);
        }
    }
}

Add the created CustomExceptionFilter to the MvcOptions.Filters collection:

public void ConfigureServices(IServiceCollection services) {
    services.AddMvc(options => { options.Filters.Add(typeof(CustomExceptionFilter));});
    services.AddScoped<DashboardConfigurator>((IServiceProvider serviceProvider) => {
        DashboardConfigurator configurator = new DashboardConfigurator();
        // ...
    });
    // ...
}

Catch the Web Dashboard’s Unhandled Exceptions

Create a custom dashboard controller (a DashboardController descendant) and provide a custom exception filter to log the Web Dashboard’s exceptions separately:

In the Startup.cs file, create a Dashboard controller descendant and attach the exception filter:

using Microsoft.AspNetCore.Mvc;

// ...

[TypeFilter(typeof(CustomExceptionFilter))]
public class MyDashboardController : DashboardController {
    public MyDashboardController(DashboardConfigurator configurator) : base(configurator) { }
}

Add a routing to a custom controller:

app.UseMvc(routes => {
    routes.MapDashboardRoute("dashboardControl", "MyDashboard", new string[] { "" });
    // ...
});

Pass the created controller’s name as the DashboardBuilder.ControllerName method’s parameter:

<div style="position: absolute; left:0;top:0;right:0;bottom:0;">
    @(Html.DevExpress().Dashboard("clientDashboardControl1")
    .Width("100%")
    .Height("100%")
    .ControllerName("MyDashboard")
    )
</div>

In result the native ASP.NET Core logger system catches all exceptions occurred in the Web Dashboard’s code.

Note

If you set the ExceptionContext.ExceptionHandled property to true, a custom exception filter starts to handle all the application’s exceptions. In this case, the built-in the Web Dashboard’s exception handling mechanism can work incorrectly and display common error text without specific details.

Catch Connection Errors

Use the DashboardConfigurator.ConnectionError event to catch and log connection errors. The ConnectionError event is fired when the current connection parameters do not allow you to connect to a data store (for instance, the database is inaccessible).

Use the created CustomExceptionFilter.AddToLog method in the event handler to write exception details to a text file:

public void ConfigureServices(IServiceCollection services) {
    // Add a DashboardController class descendant with a specified dashboard storage
    // and a connection string provider.
    services.AddMvc(options => { options.Filters.Add(typeof(CustomExceptionFilter)); }).
    services.AddScoped<DashboardConfigurator>((IServiceProvider serviceProvider) => {
        DashboardConfigurator configurator = new DashboardConfigurator();
        // ...
        configurator.ConnectionError += (s, e) => {
            CustomExceptionFilter.AddToLog(
                e.Exception, 
                Path.Combine(Env.ContentRootPath, "App_Data", "Error.log"));
        };
    });
    // ...
}

You need to assign the Env property from the Startup method to access the IHostingEnvironment.ContentRootPath property and set the absolute path:

using Microsoft.AspNetCore.Hosting;
// ...
public IHostingEnvironment Env { get; }
public Startup(IConfiguration configuration, IHostingEnvironment hostingEnvironment) {
    Env = hostingEnvironment;
    // ...
}

Use the DashboardDataLoadingException to indicate exceptions that occur during loading data to a data source.