我正在try 开始在我的新项目中使用.NET8Blazor服务器/客户端.

我有一个来自Sync Fusion的模板,并且我已经添加了ASP.NET标识功能.

我正在try 创建一个返回我的服务器日志(log)的Blazor服务器页面.

我登录,然后转到页面,我希望看到加载...当数据加载时.

好的,它似乎显示了装载...在从我的数据库返回之后,然后再次激发数据库调用,最后显示包含数据的网格.

我做错了什么?

我删除了数据库调用,然后执行了Task.Delay(1000),它也做了同样的事情.

我认为整个要点是,它可以显示加载,直到从数据库中设置了我的对象列表,然后将显示网格?

Seri-Log.Razor page:

@page "/maintenance/seri-log-server"
@using Microsoft.AspNetCore.Authorization
@using App.Client.Services
@using System.Net.Http.Headers
@using App.Shared.DTOs.SeriLog
@using App.Shared.Interfaces
@using Syncfusion.Blazor.Buttons
@using System.Text.Json
@using Syncfusion.Blazor.Grids
@using System.Net.Http.Json

@inject ILogger<SeriLogsServer> _logger;
@inject IMaintenanceStore maintenanceStore;

@attribute [Authorize]

<PageTitle>Seri Log Maintenance Server</PageTitle>


<h3>Start Local: @CurrenTimeLocalStart</h3>
<hr />

@if (Error != null)
{
    <div class="c-error">
        <h3>Error</h3>
        <h5>@Error</h5>
    </div>
}

@if (SeriLogs == null)
{
    <span>
        Loading Seri Logs......
    </span>
}
else
{
    <hr />
    <h3>End Local: @CurrenTimeLocalEnd</h3>
    <SfGrid ID="Grid" DataSource="@SeriLogs" @ref="Grid" AllowPaging="true" AllowFiltering="true" AllowReordering="true" AllowResizing="true" AllowGrouping="true" AllowExcelExport="true" AllowSelection="false">
        <GridFilterSettings Type="Syncfusion.Blazor.Grids.FilterType.FilterBar"></GridFilterSettings>
        <GridPageSettings PageSizes="true"></GridPageSettings>
        <GridSelectionSettings Type="Syncfusion.Blazor.Grids.SelectionType.Multiple"></GridSelectionSettings>
        <GridColumns>
            <GridColumn Field=@nameof(SeriLogDTO.Id) HeaderText="ID" IsPrimaryKey="true" TextAlign="TextAlign.Center" Width="120"></GridColumn>
            <GridColumn Field=@nameof(SeriLogDTO.TimeStamp) HeaderText="TimeStamp" IsPrimaryKey="false" TextAlign="TextAlign.Center" Width="120"></GridColumn>
            <GridColumn Field=@nameof(SeriLogDTO.Message) HeaderText="Message" IsPrimaryKey="false" TextAlign="TextAlign.Center" Width="500"></GridColumn>
            <GridColumn Field=@nameof(SeriLogDTO.Exception) HeaderText="Exception" IsPrimaryKey="false" TextAlign="TextAlign.Center" Width="200"></GridColumn>
            <GridColumn Field=@nameof(SeriLogDTO.MessageTemplate) HeaderText="MessageTemplate" IsPrimaryKey="false" TextAlign="TextAlign.Center" Width="300"></GridColumn>
            <GridColumn Field=@nameof(SeriLogDTO.Level) HeaderText="Level" IsPrimaryKey="false" TextAlign="TextAlign.Center" Width="200"></GridColumn>

            <GridColumn Field=@nameof(SeriLogDTO.Properties) HeaderText="Properties" IsPrimaryKey="false" TextAlign="TextAlign.Center" Width="200"></GridColumn>
            <GridColumn Field=@nameof(SeriLogDTO.LogEvent) HeaderText="LogEvent" IsPrimaryKey="false" TextAlign="TextAlign.Center" Width="200"></GridColumn>
        </GridColumns>
    </SfGrid>
}

<style>
    .c-error {
        padding: 5px;
        background: #fff0f4;
        color: #c51244;
    }
</style>

@code {

    SfGrid<SeriLogDTO>? Grid;

    private DateTime CurrenTimeLocalStart { get; set; }

    private DateTime CurrenTimeLocalEnd { get; set; }

    public IList<SeriLogDTO>? SeriLogs = null;

    public string Error = null;

    private bool isInitialized = false;


    protected override async Task OnInitializedAsync()
    {
        CurrenTimeLocalStart = DateTime.UtcNow.ToLocalTime();
        // SeriLogs = await maintenanceStore.ListRelated();
        await Task.Delay(2000);
        CurrenTimeLocalEnd = DateTime.UtcNow.ToLocalTime();
    }
}

模板项目中的其他页面加载正常(因为没有异步调用?)

App.Razor

<!DOCTYPE html>
<html lang="en">

<head>
    <meta charset="utf-8" />
    <meta name="viewport" content="width=device-width, initial-scale=1.0" />
    <base href="/" />
    <link rel="stylesheet" href="bootstrap/bootstrap.min.css" />
    <link rel="stylesheet" href="app.css" />
    <link rel="stylesheet" href="App.styles.css" />
    <link rel="icon" type="image/png" href="favicon.png" />
    <HeadOutlet />
    <link rel="stylesheet" href="_content/Syncfusion.Blazor.Themes/bootstrap5.css" />
@*     <link rel="stylesheet" href="_content/Syncfusion.Blazor.Themes/fluent.css" /> *@
    <script src="_content/Syncfusion.Blazor.Core/scripts/syncfusion-blazor.min.js" type="text/javascript"></script>
    <script src="js/localStorage.js"></script>
    <script src="js/logoutOnly.js"></script>
</head>
<body>
    <Routes />
    <script src="_framework/blazor.web.js" autostart="true"></script>
 @*    <script src="js/boot.js"></script> *@

    <script>
        // Wait until a 'reload' button appears https://stackoverflow.com/questions/59779601/auto-reconnect-blazor-serverside
        new MutationObserver((mutations, observer) => {
            if (document.querySelector('#components-reconnect-modal h5 a')) {
                // Now every 10 seconds, see if the server appears to be back, and if so, reload
                async function attemptReload() {
                    await fetch(''); // Check the server really is back
                    location.reload();
                }
                observer.disconnect();
                attemptReload();
                setInterval(attemptReload, 10000);
            }
        }).observe(document.body, { childList: true, subtree: true });
    </script>
</body>

</html>

<script>

    function isDevice() {

        return /android|webos|iphone|ipad|ipod|blackberry|iemobile|opera mini|mobile/i.test(navigator.userAgent);

    }

</script>

Route.razor:

@using App.Components.Layout
@* <Router AppAssembly="@typeof(Program).Assembly" AdditionalAssemblies="new[] { typeof(Client._Imports).Assembly }">
    <Found Context="routeData">
        <AuthorizeRouteView RouteData="@routeData" DefaultLayout="@typeof(Layout.MainLayout)" />
        <FocusOnNavigate RouteData="@routeData" Selector="h1" />
    </Found>
</Router>
 *@

 <Router AppAssembly="@typeof(Program).Assembly">
    <Found Context="routeData">
        <AuthorizeRouteView RouteData="@routeData" DefaultLayout="@typeof(MainLayout)">
            <NotAuthorized>
                <App.Components.Pages.Account.Login />
            </NotAuthorized>
        </AuthorizeRouteView>
    </Found>
    <NotFound>
        <CascadingAuthenticationState>
            <LayoutView Layout="@typeof(MainLayout)">
                <p>Sorry, there's nothing at this address.</p>
            </LayoutView>
        </CascadingAuthenticationState>
    </NotFound>
</Router>

推荐答案

Net8引入了渲染模式,并随之而来的是创建Static的各种变体的能力.活动页面和客户端呈现的页面.

这种 Select 的问题是很容易出错.

对于这个答案,我有:

  1. 部署了Blazor Web Project个模板,并 Select 了InteractiveServerPer page/component个选项.
  2. 添加了Blazr.RenderState Nuget套餐.
  3. 向服务器添加了Blazr.RenderState个服务.
builder.AddBlazrRenderStateServerServices();

正常的异步加载页面如下所示.我用await Task.Delay(2000);来伪装一个缓慢的非同步数据库数据获取.

@page "/"
@rendermode InteractiveServer
@using Blazr.RenderState
<PageTitle>Home</PageTitle>

<h1>Hello, world!</h1>

Welcome to your new app.

@if (_loading)
{
    <div class="alert alert-warning">Loading</div>
    return;
}


<div class="alert alert-success">Loaded</div>

@code {
    private bool _loading = true;

    protected override async Task OnInitializedAsync()
    {
        // emulate slow data load
        await Task.Delay(2000);
        _loading = false;
    }
}

当您第一次运行应用程序时,您会注意到:

  1. 页面预渲染时的延迟.
  2. 已加载,在预渲染完成时显示.
  3. 以交互方式加载页面时显示的加载.
  4. 装车后等待完成.

如果您转到另一个页面,然后向后导航,您将获得相同的效果,但在步骤1中,它将滞后于您要离开的页面.

这样做的原因是,应用程序设置为Per page/component,并且路由在服务器上静态呈现.在App中,它的渲染模式未设置

    <Routes />

这是SSSR组件

这意味着AppRouterMainLayoutNavMenu都是SSSR.它只有Home个,而且它的子组件是ASSR.

IBlazrRenderStateService

IBlazrRenderStateService检测预渲染,因此我们可以避免执行任何长时间运行的异步任务,并显示相同的加载页面.

此版本的页面会立即加载,并且SSSR到ASSR的上下文切换更加无缝.

@page "/Loader"
@rendermode InteractiveServer
@using Blazr.RenderState
@inject IBlazrRenderStateService RenderState
<PageTitle>Home</PageTitle>

<h1>Hello, world!</h1>

Welcome to your new app.

@if (RenderState.IsPreRender || _loading)
{
    <div class="alert alert-warning">Loading</div>
    return;
}


<div class="alert alert-success">Loaded</div>

@code {
    private bool _loading = true;

    protected override async Task OnInitializedAsync()
    {
        // exist early
        if (this.RenderState.IsPreRender)
            return;

        await Task.Delay(2000);
        _loading = false;
    }
}

OnAfterRender{Async}

OnAfterRender{Async}在这个实例中工作,因为它在预呈现时不会被调用(没有js上下文).然而,我认为在这种情况下使用它并不是一种好的做法,原因与这两个问题和答案中给出的原因相同.

你可以找到这个项目和Blazr.RenderState Repo here.

Csharp相关问答推荐

MongoDB实体框架核心:表达必须可写

C#将参数传递给具有变化引用的变量

找不到网址:https://localhost:7002/Category/Add?区域= Admin.为什么我的URL是这样生成的?area = Admin而不是/Admin/

WPF DataGrid中的三维数据

如何在没有额外副本的情况下将存储在IntPtr下的原始图像数据写入WinUI3中的Image控件?

S能够用DATETIME来计算,这有什么错呢?

从.Net 6 DLL注册和检索COM对象(Typelib导出:类型库未注册.(异常来自HRESULT:0x80131165))

如何使用EF Core和.NET 8来upsert到具有多对多关系的表?

使用带有参数和曲面的注入失败(&Q;)

EFR32BG22 BLE在SPP模式下与PC(Windows 10)不连接

该函数不能检测两条曲线的交点

委托RequestDelegate不带2个参数-ASP.NET Core 8最小API

用于ASP.NET核心的最小扩展坞

如何从SignalR获取连接客户端的域

删除MudRadio时,MudRadioGroup未 Select 正确的MudRadio

如何在.NET MAUI上在iOS和Mac之间共享代码?(no条件编译和无代码重复)

如何在Cake脚本中设置MSBuild.exe的绝对路径

处理方法内部过滤与外部过滤

实体框架允许您具有筛选的属性吗?

如何对正方形格线进行对角分组