Gestire un errore HTTP in Blazor mostrando un messaggio in popup

di Marco De Sanctis, in ASP.NET Core,

Quando in Blazor eseguiamo una chiamata HTTP, ci troviamo in un contesto di particolare fragilità, dato che l'esecuzione potrebbe non andare a buon fine per molteplici ragioni: il server potrebbe essere giù, la connessione di rete potrebbe non essere disponibile, o magari ci viene restuito uno status code 500 (Internal Server Error) a causa di un bug sul nostro web service.

Sfortunatamente in Blazor non esiste un gestore delle eccezioni centralizzato, quindi l'unica alternativa che abbiamo è crearci un wrapper di HttpClient tramite cui effettuare le chiamate in maniera controllata.

Una semplice implementazione potrebbe essere quella del codice in basso:

public class SafeHttpClient
{
    private HttpClient _client;
    private IModalService _modal;

    public SafeHttpClient(HttpClient client, IModalService modal)
    {
        _client = client;
        _modal = modal;
    }

    public async Task<T> ExecuteAsync<T>(Func<HttpClient, Task<T>> httpCall)
    {
        try
        {
            return await httpCall(_client);
        }
        catch (HttpRequestException e) when (e.StatusCode == HttpStatusCode.InternalServerError)
        {
            Console.WriteLine($"Error intercepted {e.StatusCode}");

            var parameters = new ModalParameters();
            parameters.Add(nameof(SimpleMessage.Message), 
              "Il server ha restituito un errore, si consiglia di riprovare più tardi");

            _modal.Show<SimpleMessage>("Errore durante la chiamata di rete", parameters);

            return default(T);
        }
    }
}

Questa classe espone un metodo ExecuteAsync a cui possiamo passare un delegate asincrono, ossia un frammento di codice che accetti in ingresso un HttpClient e restituisca un generico Task<T>.

La logica è banale, e si limita semplicemente a effettuare la chiamata all'interno di un blocco Try...Catch. Nel caso di InternalServerError, il codice sfrutta il componente Blazored.Modal (https://github.com/Blazored/Modal) per mostrare una popup con un generico messaggio di errore.

La finestra modale si basa su un componente SimpleMessage.razor che accetta un parametro per il messaggio da mostrare:

<div>

    <p>@Message</p>

    <button @onclick="Cancel" class="btn btn-primary">Ok</button>
</div>

@code {
    [CascadingParameter] BlazoredModalInstance BlazoredModal { get; set; }

    [Parameter] public string Message { get; set; }

    async Task Cancel() => await BlazoredModal.CancelAsync();
}

Come al solito, dobbiamo ricordarci di registrare i componenti necessari nell'IoC container di Blazor:

public static async Task Main(string[] args)
{
    // ... altro codice qui ...
    builder.Services.AddHttpClient("default", httpclient =>
    {
        httpclient.BaseAddress = new Uri(builder.HostEnvironment.BaseAddress);
    });

    builder.Services.AddTransient(sp => sp.GetRequiredService<IHttpClientFactory>().CreateClient("default"));
    builder.Services.AddBlazoredModal();
    builder.Services.AddTransient<SafeHttp>();

    ...
    await builder.Build().RunAsync();
}

Se abbimo svolto tutti i passaggi correttamente, possiamo modificare la pagina FetchData.razor del template di esempio di Blazor e sfruttare la nostra nuova classe SafeHttpClient in questo modo:

@page "/fetchdata"
@inject SafeHttpClient SafeHttpClient

...

@code {
    private WeatherForecast[] forecasts;

    protected override async Task OnInitializedAsync()
    {
        forecasts = await SafeHttpClient.ExecuteAsync(
          http => http.GetFromJsonAsync<WeatherForecast[]>("WeatherForecast"));
    }
}

Una nota da fare riguarda il fatto che l'extension method GetFromJsonAsync tramite cui effettuiamo la chiamata, verifica al suo interno il successo della stessa invocando EnsureSuccessStatusCode di HttpResponseMessage; quest'ultimo solleva una HttpRequestException nel caso in cui ci sia stato un errore. Se invece abbiamo utilizzato i metodi GetAsync, PostAsync, e via discorrendo, dobbiamo ricordarci di chiamare manualmente EnsureSuccessStatusCode, perché altrimenti non verrà sollevata alcuna eccezione in caso di errore dal server.

Commenti

Visualizza/aggiungi commenti

| Condividi su: Twitter, Facebook, LinkedIn

Per inserire un commento, devi avere un account.

Fai il login e torna a questa pagina, oppure registrati alla nostra community.

Approfondimenti

I più letti di oggi