Author : MD TAREQ HASSAN | Updated : 2020/08/21

Handling exceptions in Blazor

AppException class

Exceptions/AppException.cs

/// <summary>
/// App realted exception. Page components will catch this exception and show error to UI.
/// </summary>
public class AppException : Exception
{
	/// <summary>
	/// Exception with message and inner exception
	/// </summary>
	/// <param name="message"></param>
	/// <param name="exception"></param>
	public AppException(string message, Exception exception) : base(message, exception)
	{
	}

	/// <summary>
	/// Exception with message only
	/// </summary>
	/// <param name="message"></param>
	/// <param name="exception"></param>
	public AppException(string message) : base(message)
	{
	}
}

Exception handling and logging in service

Services/IFooService.cs

/// <summary>
/// Service/domain interface
/// </summary>
public interface IFooService
{
	// ... ... ...
	
	/// <summary>
	/// Find foo data list.
	/// </summary>
	/// <returns>List<FooModel> - foo data list</returns>
	Task<FooModel> FetchFooAsync();
	
	// ... ... ...
}

Services/FooService.cs

using AutoMapper;
using Microsoft.EntityFrameworkCore;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Threading.Tasks;
using Serilog;
using Microsoft.Extensions.Configuration;
using Microsoft.AspNetCore.Http;


/// <summary>
/// Implementation of service contract/interface
/// </summary>
public class FooService : IFooService
{
	private readonly FooDbContext _dbContext;
    private readonly IMapper _mapper;
	
	// ... ... ...

	public FooService(FooDbContext dbContext, IMapper mapper //, ... ... ...)
	{
		_dbContext = dbContext;
		_mapper = mapper;
		
		// ... ... ...
	}
	
	/// <inheritdoc />
	public async Task<FooModel> FetchFooAsync()
	{
		try
		{
			var entityList = await _dbContext.Foos.ToListAsync();

			var fooList = _mapper.Map<List<FooModel>>(entityList);

			return fooList;
		}
		catch (Exception ex)
		{
			Log.Error(ex.Message, ex);
			throw new AppException("Error occured while fetching email data");
		}
	}
	
	// ... ... ...
}

Handling and showing error in page component

Pages/Index.razor.cs

public class IndexBase : ComponentBase
{	
	// ... ... ...
	
	[Inject]
	protected IFooService FooService { get; set; }

	protected string ErroMessage { get; set; } = string.Empty;

	protected List<FooModel> FooList = default;
	
	// ... ... ...


	protected override async Task OnInitializedAsync()
	{

		Log.Information("Initializing required data");

		ErroMessage = string.Empty;

		try
		{

			FooList = await FooService.FetchFooAsync();
			
			// ... ... ...
		}
		catch (AppException ex) // logging will be done in service
		{
			ErroMessage = ex.Message;
		} 
		catch (Exception ex) // do logging
		{
			Log.Error(ex.Message, ex);
			ErroMessage = "Unexpected error occured!";
		}
	}

	// ... ... ...
}

Pages/Index.razor

@page "/"
@page "/foos"
@inherits IndexBase

// ... ... ...

<div class="...">

	if (!string.IsNullOrWhiteSpace(ErroMessage))
	{
		<h3>@ErroMessage</h3>
	}
	else
	{
		@if (FooList == null || !FooList.Any())
		{
			<h3>Loading...</h3>
		}
		else
		{
			@foreach (var foo in FooList)
			{
				// use foo
				
				// ... ... ...
			}
		}
	}
	
</div>

Detailed error

Startup.cs

public class Startup
{
	// ... ... ...

	public void ConfigureServices(IServiceCollection services)
	{
	
		// ... ... ...
		
		services.AddServerSideBlazor().AddCircuitOptions(options => { options.DetailedErrors = true; });
		
		// ... ... ...
	}

	public void Configure(IApplicationBuilder app, IWebHostEnvironment env)
	{
		// ... ... ...
	}
}