Open hikalkan opened 3 years ago
Good day, this fix gonna be available on version 5.4?
Good day, this fix gonna be available on version 5.4?
Yes, we expect it to be available on version 6.0.
Any updates on this one?
There have been investigations, but the results were unsatisfactory due to some limitations. However, we will close the problem once we have found a satisfactory solution.
So what's the workaround so far? Catching the exception in the component's code on the Blazor side?
If so, how do I open the exception modal with the message?
Yes, we try to ensure that there are no unhandled exceptions as mentioned in Microsoft's documentation.
By the way, you can see the work done within the scope of this issue here.
Abp 7.3.3 Dotnet core 7
It can be done easily by creating the ComponentBase
from scratch just like the original (github):
in blazor components, every events will be called from Task IHandleEvent.HandleEventAsync
so if it can be override, then we can create a handler based on the Task.Status
MyComponentBase
:
public abstract class MyComponentBase : IComponent, IHandleEvent, IHandleAfterRender
{
...
Task IHandleEvent.HandleEventAsync(EventCallbackWorkItem callback, object? arg)
{
var task = callback.InvokeAsync(arg);
var shouldAwaitTask = task.Status != TaskStatus.RanToCompletion &&
task.Status != TaskStatus.Canceled;
// After each event, we synchronously re-render (unless !ShouldRender())
// This just saves the developer the trouble of putting "StateHasChanged();"
// at the end of every event callback.
StateHasChanged();
return shouldAwaitTask ?
CallStateHasChangedOnAsyncCompletion(task) :
Task.CompletedTask;
}
...
}
Then task will be run in CallStateHasChangedOnAsyncCompletion
method:
private async Task CallStateHasChangedOnAsyncCompletion(Task task)
{
try
{
await task;
}
catch // avoiding exception filters for AOT runtime support
{
// Ignore exceptions from task cancellations, but don't bother issuing a state change.
if (task.IsCanceled)
{
return;
}
throw;
}
StateHasChanged();
}
throw
call a method for handle the task.Exception
named OnCallStateHasChangedOnAsyncCompletionExceptionAsync
:protected virtual Task OnCallStateHasChangedOnAsyncCompletionExceptionAsync(AggregateException? exception)
=> Task.CompletedTask;
Make sure to set the virtual
keyword to allow override this method.
private async Task CallStateHasChangedOnAsyncCompletion(Task task)
{
try
{
await task;
}
catch // avoiding exception filters for AOT runtime support
{
// Ignore exceptions from task cancellations, but don't bother issuing a state change.
if (task.IsCanceled)
{
return;
}
await OnCallStateHasChangedOnAsyncCompletionExceptionAsync(task.Exception);
}
StateHasChanged();
}
From OwningComponentBase
and AbpComponentBase
rewrite it to MyOwningComponentBase
and MyAbpComponentBase
.
In MyAbpComponentBase
, the OnCallStateHasChangedOnAsyncCompletionExceptionAsync
method can be override like this:
protected override Task OnCallStateHasChangedOnAsyncCompletionExceptionAsync(AggregateException? exception)
{
return HandleErrorAsync(exception);
}
HandleErrorAsync
is a method in MyAbpComponentBase
that appear a friendly modal message.
In the RunInitAndSetParametersAsync
method also can do the same for handle errors.
private async Task RunInitAndSetParametersAsync()
{
try
{
...
}
catch (Exception ex)
{
await OnRunInitAndSetParametersExceptionAsync(ex);
}
}
public virtual Task OnRunInitAndSetParametersExceptionAsync(Exception ex) => Task.CompletedTask;
In MyAbpComponentBase
:
public override Task OnRunInitAndSetParametersExceptionAsync(Exception ex)
{
return HandleErrorAsync(ex);
}
With Regards
I bumped into it in ABP 7.4.0 commercial: Unhandled exception rendering component: Forbidden Volo.Abp.Http.Client.AbpRemoteCallException
I bumped into it in ABP 7.4.0 commercial:
Unhandled exception rendering component: Forbidden Volo.Abp.Http.Client.AbpRemoteCallException
Please check the logs of the backend app, and create a new issue. Thanks.
Abp 7.3.3 Dotnet core 7
It can be done easily by creating the
ComponentBase
from scratch just like the original (github):in blazor components, every events will be called from
Task IHandleEvent.HandleEventAsync
so if it can be override, then we can create a handler based on theTask.Status
- Create the
MyComponentBase
:public abstract class MyComponentBase : IComponent, IHandleEvent, IHandleAfterRender { ... Task IHandleEvent.HandleEventAsync(EventCallbackWorkItem callback, object? arg) { var task = callback.InvokeAsync(arg); var shouldAwaitTask = task.Status != TaskStatus.RanToCompletion && task.Status != TaskStatus.Canceled; // After each event, we synchronously re-render (unless !ShouldRender()) // This just saves the developer the trouble of putting "StateHasChanged();" // at the end of every event callback. StateHasChanged(); return shouldAwaitTask ? CallStateHasChangedOnAsyncCompletion(task) : Task.CompletedTask; } ... }
Then task will be run in
CallStateHasChangedOnAsyncCompletion
method:private async Task CallStateHasChangedOnAsyncCompletion(Task task) { try { await task; } catch // avoiding exception filters for AOT runtime support { // Ignore exceptions from task cancellations, but don't bother issuing a state change. if (task.IsCanceled) { return; } throw; } StateHasChanged(); }
- Instead of
throw
call a method for handle thetask.Exception
namedOnCallStateHasChangedOnAsyncCompletionExceptionAsync
:protected virtual Task OnCallStateHasChangedOnAsyncCompletionExceptionAsync(AggregateException? exception) => Task.CompletedTask;
Make sure to set the
virtual
keyword to allow override this method.
- Now CallStateHasChangedOnAsyncCompletion would be like this:
private async Task CallStateHasChangedOnAsyncCompletion(Task task) { try { await task; } catch // avoiding exception filters for AOT runtime support { // Ignore exceptions from task cancellations, but don't bother issuing a state change. if (task.IsCanceled) { return; } await OnCallStateHasChangedOnAsyncCompletionExceptionAsync(task.Exception); } StateHasChanged(); }
- From
OwningComponentBase
andAbpComponentBase
rewrite it toMyOwningComponentBase
andMyAbpComponentBase
.- In
MyAbpComponentBase
, theOnCallStateHasChangedOnAsyncCompletionExceptionAsync
method can be override like this:protected override Task OnCallStateHasChangedOnAsyncCompletionExceptionAsync(AggregateException? exception) { return HandleErrorAsync(exception); }
HandleErrorAsync
is a method inMyAbpComponentBase
that appear a friendly modal message.In the
RunInitAndSetParametersAsync
method also can do the same for handle errors.private async Task RunInitAndSetParametersAsync() { try { ... } catch (Exception ex) { await OnRunInitAndSetParametersExceptionAsync(ex); } } public virtual Task OnRunInitAndSetParametersExceptionAsync(Exception ex) => Task.CompletedTask;
In
MyAbpComponentBase
:public override Task OnRunInitAndSetParametersExceptionAsync(Exception ex) { return HandleErrorAsync(ex); }
With Regards
i noticed some information being missed, for example , the ```StateHasChanged()``` method does not exist in the custom component base , also , the ```HandleErrorAsync()``` method is only available if you inherits from ```AbpComponentBase```
i quit liked the solution but the implementation needs more detail.
also , i think it's time for @Abp to think about a solution to handle errors generally.
Thanks.
Any progress on this one?
We'd implemented a custom logger to show errors for Blazor WASM. For server side, global exception handling is not possible yet (see https://github.com/dotnet/aspnetcore/issues/30940). However, we can still show a better messagebox (modal dialog) instead of the yellow bottom bar, for blazor server side. We can provide an option to the user to refresh the page in this modal dialog (message modal can have two options: Close & Refresh Page). However, this should be carefully implemented. Because, if we handle every error and try to show message, it won't work. We should only handle the errors for blazor application's page, not other HTTP requests and MVC page requests.