'Exception not handling globally in .net core blazor

I have API calls utility in my blazor web project. I have added condition where if I get unauthorized response from API, I am throwing the unauthorized error and trying to catch it in program.cs file so I can redirect user to login page. while throwing error blazor engine returning error in browser.

Utitlity.cs

        public async Task<CurrentResponse> GetAsync(IHttpClientFactory _httpClient, string url)
        {

            try
            {
                var request = new HttpRequestMessage(HttpMethod.Get, url);
                request.Headers.Clear();
                request.Headers.Authorization = new AuthenticationHeaderValue("Bearer", GetClaimValue(CustomClaimTypes.AccessToken));

                var client = _httpClient.CreateClient("FSMAPI");

                HttpResponseMessage httpResponseMessage = await client.SendAsync(request);

                if(httpResponseMessage.StatusCode == System.Net.HttpStatusCode.Unauthorized)
                {
                    ManageUnAuthorizedError();
                }

                CurrentResponse response = JsonConvert.DeserializeObject<CurrentResponse>(httpResponseMessage.Content.ReadAsStringAsync().Result);

                return response;
            }
            catch (Exception exc)
            {
                throw exc;
            }
        }

        private void ManageUnAuthorizedError(/*IHttpClientFactory _httpClient*/)
        {
            throw new UnauthorizedAccessException(HttpStatusCode.Unauthorized.ToString());
        }

Program.cs

app.UseExceptionHandler(c => c.Run(async context =>
{
    var exception = context.Features
        .Get<IExceptionHandlerPathFeature>()
        .Error;

    var response = new { error = exception.Message };

    if(exception.Message == HttpStatusCode.Unauthorized.ToString())
    {
        context.Response.Redirect("/Login");
    }
}));

getting in built error



Solution 1:[1]

Here's a possible solution based on the information you've provided in the question.

You need to interact with the UI through Services

A notification service:

public class NeedToAuthenticateService
{
    public string ErrorMessage { get; set; } = string.Empty;

    public event EventHandler? AuthenticationRequired;

    public void NotifyAuthenticationRequired()
        => AuthenticationRequired?.Invoke(this, new EventArgs()); 
}

This is a "simple" emulation of your API call done through a service that interfaces with the NeedToAuthenticateService and raises the AuthenticationRequired event.

public class APIReaderService
{
    private NeedToAuthenticateService needToAuthenticateService;

    public APIReaderService(NeedToAuthenticateService needToAuthenticateService)
    {
        this.needToAuthenticateService = needToAuthenticateService;
    }

    public void GetData()
    {
        // If you get an error
        needToAuthenticateService.ErrorMessage = "You need to log in!";
        needToAuthenticateService.NotifyAuthenticationRequired();
    }
}

A simple demo Login page showing the message.

@page "/Logon"
<h3>Logon</h3>
@inject NeedToAuthenticateService needToAuthenticateService

<div class="p-3">
    @this.needToAuthenticateService.ErrorMessage
</div>

@code {

}

A modified MainLayout page which registers and event handler with NeedToAuthenticateService and triggers a navigate event when AuthenticationRequired is raised.

@inherits LayoutComponentBase
@inject NeedToAuthenticateService needToAuthenticateService
@inject NavigationManager NavManager
@implements IDisposable

<PageTitle>BlazorApp1</PageTitle>

<div class="page">
    <div class="sidebar">
        <NavMenu />
    </div>

    <main>
        <div class="top-row px-4">
            <a href="https://docs.microsoft.com/aspnet/" target="_blank">About</a>
        </div>

        <article class="content px-4">
            @Body
        </article>
    </main>
</div>

@code {
    protected override void OnInitialized()
     => this.needToAuthenticateService.AuthenticationRequired += GoToLogIn;

    private void GoToLogIn(object? sender, EventArgs e)
        => NavManager.NavigateTo("/Logon");

    public void Dispose()
     => this.needToAuthenticateService.AuthenticationRequired -= GoToLogIn;
}

And finally the registered services in Program

builder.Services.AddSingleton<WeatherForecastService>();
builder.Services.AddScoped<APIReaderService>();
builder.Services.AddScoped<NeedToAuthenticateService>();

Sources

This article follows the attribution requirements of Stack Overflow and is licensed under CC BY-SA 3.0.

Source: Stack Overflow

Solution Source
Solution 1 MrC aka Shaun Curtis