es.davy.ai

Preguntas y respuestas de programación confiables

¿Tienes una pregunta?

Si tienes alguna pregunta, puedes hacerla a continuación o ingresar lo que estás buscando.

¿Por qué mi aplicación de Blazor Server espera para renderizarse hasta que se haya recuperado los datos, incluso cuando se usa async?

Estoy construyendo una aplicación de Blazor Server usando .NET 6.
Como ejemplo, tengo una lista de clientes que obtengo de una base de datos Sqlite utilizando Entityframework Core. Quiero mostrar un indicador de carga cuando los datos aún se están obteniendo. De la siguiente manera:

@page "/customers"
@inject CustomerService CustomerService

@if(customers.Count == 0)
{
    <p>Cargando...</p>
}
else
{
    <table>
        @foreach(Customer customer in customers)
        {
            <tr>
                <td>
                    @customer.Id
                </td>
                <td>
                    @customer.Name
                </td>
            </tr>
        }
    </table>
}

Cuando uso la siguiente implementación de datos, funciona bien:

private List<customer> customers = new();

protected async override Task OnInitializedAsync()
{
    await Task.Run(() =>
    {
        this.customers = CustomerService.GetCustomers();
    });
}

Sin embargo, cuando uso la siguiente implementación de datos, no funciona. Lo que significa que la página entera solo se vuelve visible una vez que los datos se han cargado (página en blanco mientras espera).

private List<customer> customers = new();

protected async override Task OnInitializedAsync()
{
    this.customers = await CustomerService.GetCustomersAsync();
}

CustomerService.cs

public class CustomerService
{
    private CustomerContext _customerContext;

    public CustomerService(CustomerContext customerContext)
    {
        _customerContext = customerContext;
    }

    public async Task<><customer>> GetCustomersAsync()
    {
        return await _customerContext.Customers.ToListAsync();
    }

    public List<customer> GetCustomers()
    {
        return _customerContext.Customers.ToList();
    }
}

Esperaría que mi segunda implementación también funcione de forma asíncrona. ¿Podría alguien ayudarme a entender, por favor? ¿Qué me falta aquí? ¡Gracias de antemano por la ayuda!

Tags:  , , ,

Answer

  1. Avatar for davy.ai

    La razón por la cual la segunda implementación no está funcionando como se espera es porque no está utilizando la palabra clave await en la llamada a Task.Run(), lo que significa que el método continuará de forma sincrónica y bloqueará el hilo de la interfaz de usuario hasta que la tarea se complete.

    En cambio, la palabra clave await en la segunda implementación espera correctamente a que la tarea se complete de forma asíncrona antes de continuar con el resto del método.

    Para que la primera implementación también funcione de forma asíncrona, debes reemplazar:

    Task.Run(() =>
    {
        this.customers = CustomerService.GetCustomers();
    });
    

    con:

    this.customers = await Task.Run(() =>
    {
        return CustomerService.GetCustomers();
    });
    

    Esto ejecutará de forma asíncrona el método GetCustomers() en un hilo separado y esperará su finalización, al mismo tiempo que actualiza la interfaz de usuario con el indicador de carga hasta que los datos estén listos para ser mostrados.

    Alternativamente, si deseas mantener la estructura original del código sin utilizar Task.Run(), también puedes utilizar el método ConfigureAwait(false) para evitar capturar el contexto de la interfaz de usuario y permitir que la tarea se ejecute en un hilo separado:

    protected async override Task OnInitializedAsync()
    {
        this.customers = await CustomerService.GetCustomers().ConfigureAwait(false);
    }
    

    Esto también permitirá que la interfaz de usuario se actualice con el indicador de carga mientras se ejecuta la tarea.

Comments are closed.