Skip to content
This repository has been archived by the owner on Nov 1, 2024. It is now read-only.

Commit

Permalink
Forward exceptions to root ViewModel for handling
Browse files Browse the repository at this point in the history
  • Loading branch information
ligowsky authored Aug 5, 2024
1 parent 48b75af commit 651ffa8
Show file tree
Hide file tree
Showing 4 changed files with 95 additions and 30 deletions.
19 changes: 19 additions & 0 deletions src/BitzArt.Blazor.MVVM/Components/PageBase{TViewModel}.cs
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,25 @@ public abstract class PageBase<TViewModel> : ComponentBase<TViewModel>, IStateCo

private const string StateKey = "state";

public delegate Task PageExceptionHandler(object sender, Exception ex);

/// <summary>
/// Called when an exception is thrown within the scope of the page and needs to be handled.
/// </summary>
public PageExceptionHandler? ExceptionHandler { get; set; }

override protected void OnInitialized()
{
base.OnInitialized();
ViewModel.ExceptionHandler += (sender, ex) =>
{
if (ExceptionHandler is null)
return Task.CompletedTask;

return ExceptionHandler.Invoke(sender, ex);
};
}

protected override async Task RestoreStateAsync()
{
var state = await Js.InvokeAsync<string?>("getInnerText", [StateKey]);
Expand Down
8 changes: 8 additions & 0 deletions src/BitzArt.Blazor.MVVM/Services/ViewModelFactory.cs
Original file line number Diff line number Diff line change
Expand Up @@ -75,6 +75,14 @@ public ViewModel Create(IServiceProvider serviceProvider, Type viewModelType, Co
if (injectedViewModel.OnComponentStateContainerWasSet is not null)
await injectedViewModel.OnComponentStateContainerWasSet.Invoke(container);
};

injectedViewModel.ExceptionHandler += async (sender, exception) =>
{
if (viewModel.ExceptionHandler is null)
return;

await viewModel.ExceptionHandler.Invoke(sender, exception);
};
}

else if (injection.IsParentViewModelInjection)
Expand Down
68 changes: 68 additions & 0 deletions tests/BitzArt.Blazor.MVVM.Tests/ExceptionHandlingTests.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,68 @@
using BitzArt.Blazor.MVVM.Tests.ViewModels;
using Microsoft.Extensions.DependencyInjection;

namespace BitzArt.Blazor.MVVM.Tests;

public class ExceptionHandlingTests
{
[Fact]
public async Task HandleAsync_WhenExceptionIsThrown_ShouldInvokeExceptionHandler()
{
// Arrange
var viewModel = new TestLayer1ViewModel();
var exceptionHandlerInvoked = false;

viewModel.ExceptionHandler = (sender, ex) =>
{
exceptionHandlerInvoked = true;
return Task.CompletedTask;
};

// Act
try
{
await viewModel.HandleAsync(() => throw new Exception());
}
catch (Exception)
{
}

// Assert
Assert.True(exceptionHandlerInvoked);
}

[Fact]
public async Task HandleAsync_HierarchicalStructure_ShouldForwardToRoot()
{
// Arrange

var serviceCollection = new ServiceCollection();
serviceCollection.AddBlazorMvvm()
.AddViewModel<TestLayer1ViewModel>()
.AddViewModel<TestLayer2ViewModel>();

var serviceProvider = serviceCollection.BuildServiceProvider();

var rootViewModel = serviceProvider.GetRequiredService<TestLayer1ViewModel>();
var childViewModel = rootViewModel.TestLayer2ViewModel;

var rootExceptionHandlerInvoked = false;
rootViewModel.ExceptionHandler += (sender, ex) =>
{
rootExceptionHandlerInvoked = true;
return Task.CompletedTask;
};

// Act
try
{
await childViewModel.HandleAsync(() => throw new Exception());
}
catch (Exception)
{
}

// Assert
Assert.True(rootExceptionHandlerInvoked);
}
}

This file was deleted.

0 comments on commit 651ffa8

Please sign in to comment.