当服务器中的数据可用时更新Blazor组件

问题描述

这是一篇很长的文章,您可以帮助我为我的问题陈述提供sudo代码/通用的良好编码实践,或者查看我的完整代码(如下)并建议更改。 blazor的新手。

问题陈述:

在我的Blazor Server应用程序中,我有一个显示两个选项卡2020、2021的组件。每个选项卡都从数据库中检索其数据。我模拟了使用Task.Delay进行数据检索的延迟,分别为2秒和3秒。每个标签页(因此2020年将需要2秒加载,而2021年将需要3秒加载) 我的问题是我应该如何设置我的组件,以便在加载数据时显示加载消息,并且一旦有任何一个的数据可用,就向用户显示数据,同时继续为仍然存在的另一个显示加载消息加载中。

我在网上看到了很多建议使用Task.WhenAll的示例,但我想我的情况将需要Task.WhenAny。在这方面也需要更加明确。 标签2020是第一个标签认情况下处于打开状态,标签2021是第二个标签,您必须单击它才能打开它。

当前行为:

一旦我进入主页(两个选项卡所在的位置)并等待足够的时间直到加载所有数据(2020年和2021年),然后继续在选项卡之间切换,一切都会按预期进行。但是,如果我登陆主页后很快导航到2021选项卡,则会出现“正在加载数据..”消息(这很好,因为数据仍在加载中),但它永远不会消失。导航到2020选项卡,任务完成后即可看到数据。但是2021年处于“正在加载数据”的永久状态。

这是我的组件标记(Home.razor):

@page "/"
@inherits HomeComponentBase
<RadzenTabs>
        <Tabs>
            <RadzenTabsItem Text="2020" @onclick="OnTab2020_Click">
                @if (MonthlyFinancial_2020 == null)
                {
                    <div>Loading Data..</div>
                }
                <div>
                    <canvas id="monthlyExpenseChart_2020"></canvas>
                </div>
            </RadzenTabsItem>
            <RadzenTabsItem Text="2021" @onclick="OnTab2021_Click">
                @if (MonthlyFinancial_2021 == null)
                {
                    <div>Loading Data..</div>
                }
                <div>
                    <canvas id="monthlyExpenseChart_2021"></canvas>
                </div>
            </RadzenTabsItem>
        </Tabs>
    </RadzenTabs>

(HomeComponentBase.cs)后面的代码

using Microsoft.AspNetCore.Components;
using Microsoft.AspNetCore.Components.Web;
using Microsoft.Extensions.Logging;
using Microsoft.JSInterop;
using Newtonsoft.Json;
using RentalPropertyManagement.Models;
using RentalPropertyManagement.Services;
using Serilog;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Runtime.CompilerServices;
using System.Threading.Tasks;
using System.Web;

namespace RentalPropertyManagement.Pages
{
    public class HomeComponentBase : ComponentBase
    {
        public string Title = "4 cedar Ave.";
        public IEnumerable<MonthlyFinancial> MonthlyFinancial_2020 { get; set; }
        public IEnumerable<MonthlyFinancial> MonthlyFinancial_2021 { get; set; }
        [Inject]
        public DBService DBService { get; set; }
        [Inject]
        public IJSRuntime JSRuntime { get; set; }
        /*
            Use the OnAfterRenderAsync lifecycle method for DB calls as I want to make data available to 
            ChartJS javascript functions
        */
        protected override async Task OnAfterRenderAsync(bool firstRender)
        {
            Log.information("firstRender: " + firstRender);
            if (firstRender)
                try
                {
                    var t1 = DBService.GetMonthlyFinancial("2020"); //Start a task to call DB for year 2020 (takes 2 sec to retrieve this data)
                    var t2 = DBService.GetMonthlyFinancial("2021"); //Start a task to call DB for year 2021 (takes 3 sec to retrieve this data)

                    var myTasks = new List<Task> { t1,t2 };//Put tasks in a tasks list
                    while (myTasks.Count > 0) //loop through task list,evicting as they finish.
                    {
                        Log.information(firstRender + " About to start tasks");
                        Task finishedTask = await Task.WhenAny(myTasks); //Await on any task
                        Log.information(firstRender + " One of the tasks have finished");
                        if (finishedTask == t1) // t1 complete? Great get its data assign to a variable and call my javascript function
                        {
                            MonthlyFinancial_2020 = t1.Result;
                            Log.information(firstRender + " t1 got data");
                            StateHasChanged(); //Tell component not to display Loading message any more,but instead show the data for 2020 (I think I may be running into issue due to this as StateHasChanged calls OnAfterRenderAsync again)
                            await JSRuntime.InvokeVoidAsync("generateMonthlyExpenseChart_2020",JsonConvert.SerializeObject(MonthlyFinancial_2020));
                        }
                        else if (finishedTask == t2) // t2 complete? Great get its data assign to a variable and call my javascript function
                        {
                            MonthlyFinancial_2021 = t2.Result;
                            Log.information(firstRender + " t2 got data");
                            StateHasChanged(); //Tell component not to display Loading message any more,but instead show the data for 2021 (I think I may be running into issue due to this as StateHasChanged calls OnAfterRenderAsync again)
                            await JSRuntime.InvokeVoidAsync("generateMonthlyExpenseChart_2020",JsonConvert.SerializeObject(MonthlyFinancial_2020));
                        }
                        myTasks.Remove(finishedTask); //evict finished tasks
                    }

                }
                catch (Exception e)
                {
                    Log.information(e.Message);
                }
        }

        public async Task OnTab2020_Click()
        {
            if (MonthlyFinancial_2020 != null)
            {
                await JSRuntime.InvokeVoidAsync("generateMonthlyExpenseChart_2020",JsonConvert.SerializeObject(MonthlyFinancial_2020));
                //StateHasChanged();
            }
        }

        public async Task OnTab2021_Click()
        {
            if (MonthlyFinancial_2021 != null)
            {
                await JSRuntime.InvokeVoidAsync("generateMonthlyExpenseChart_2021",JsonConvert.SerializeObject(MonthlyFinancial_2021));
                //StateHasChanged();
            }
        }
    }
}

数据库服务类。注意Task.Delay以模拟延迟。 (DBService.cs):

using Microsoft.AspNetCore.Mvc;
using Microsoft.Extensions.Logging;
using RentalPropertyManagement.Models;
using System;
using System.Collections.Generic;
using System.Data;
using System.Data.sqlClient;
using System.IO;
using System.Linq;
using System.Threading.Tasks;
using Serilog;
using System.Threading;

namespace RentalPropertyManagement.Services
{
    public class DBService
    {
        private string connString = @"Server=****";
        private string qryToOpen;
        private StreamReader file;
        private string sql;
        public IDbConnection Connection
        {
            get
            {
                return new sqlConnection(connString);
            }
        }

        public async Task<IEnumerable<MonthlyFinancial>> GetMonthlyFinancial(string year)
        {
            qryToOpen = "GetMonthlyFinancial.sql";
            file = new StreamReader(Constants.CURRDIR_Queries + qryToOpen);
            sql = file.ReadToEnd();
            file.Close();
            var parameter = new { Year = year };
            try
            {
                using (IDbConnection dbConnection = Connection)
                {
                    dbConnection.open();
                    Log.information("Parameter:\n" + "@Year:" + parameter.Year);
                    Log.information("Query: " + sql);
                    if(year.Equals("2020"))
                        await Task.Delay(2000);
                    if(year.Equals("2021"))
                        await Task.Delay(3000);
                    return await dbConnection.QueryAsync<MonthlyFinancial>(sql,parameter);
                }
            }
            catch (Exception e)
            {
                Log.information("Exception cccurred while retriving data from database\n" + "Exception detail: " + e.Message);
                return null;
            }
        }

    }
}

模型(MonthlyFinancial.cs):

using System.Collections.Generic;
using System.Linq;
using System.Threading.Tasks;

namespace RentalPropertyManagement.Models
{
    public class MonthlyFinancial
    {
        public int Year { get; set; }
        public string Month { get; set; }
        public float Expenditure { get; set; }
        public float Income { get; set; }
        public float Net { get; set; }
    }
}

解决方法

暂无找到可以解决该程序问题的有效方法,小编努力寻找整理中!

如果你已经找到好的解决方法,欢迎将解决方案带上本链接一起发送给小编。

小编邮箱:dio#foxmail.com (将#修改为@)