【问题标题】:JavaScript interop Error when calling javascript from OnInitializedAsync Blazor从 OnInitializedAsync Blazor 调用 javascript 时出现 JavaScript 互操作错误
【发布时间】:2025-12-03 09:20:07
【问题描述】:

我正在关注来自 NDC Oslo 的示例应用程序,即此应用程序:https://github.com/SteveSandersonMS/presentation-2019-06-NDCOslo/tree/master/demos/MissionControl。 这将 JWT 实现为身份验证和授权。但是,当我尝试将代码的实现复制到服务器端 Blazor 时,当我尝试从下面描述的本地存储中获取存储的 JWT 令牌时出现错误“

JavaScript interop calls cannot be issued at this time. This is because the component is being 
statically rendererd. When prerendering is enabled, JavaScript interop calls can only be performed 
during the OnAfterRenderAsync lifecycle method.

这是我的 Blazor 代码

protected override async Task OnInitializedAsync()
{
    var token = await TokenProvider.GetTokenAsync();
    Branches = await Http.GetJsonAsync<List<BranchDto>>(
        "vip/api/lookup/getbranches",
        new AuthenticationHeaderValue("Bearer", token));
}

错误来自

public async Task<string> GetTokenAsync()
{
   //Code Omitted for brevity 
   //This line of code is equivalent to the IJSRuntime.Invoke<string>("localstorage.getitem","authToken") 
   //change to use Blazore.LocalStorage.
    var token = await _localStorageService.GetItemAsync<string>("authToken");
    return token;
 }

我尝试在 OnAfterRenderAsync(bool firstRender) 上执行代码,错误消失了,但绑定到 API 请求的网格没有显示。 API 请求必须填充网格的数据源,该数据源必须是 OnInitializedAsync。有什么解决方法吗?

更新! 我移动了代码 OnAfterRenderAsync 并添加了 StateHasChanged 方法,我得到了所需的行为。 我忘记了用于渲染的连接是 signalR 连接。

【问题讨论】:

  • @poke 我想知道为什么 NDC 示例工作得很好。很好地抓住了我的指点。
  • 演示在 ASP.NET Core 3.0 上运行,甚至可能是预览版,所以那里的情况可能略有变化。
  • 我同意。由于它在他们的文档中,我认为我将主要关注令牌和授权的完成方式

标签: asp.net-core blazor-server-side asp.net-blazor


【解决方案1】:

根据“Detect when a Blazor Server app is prerendering”,您只能在OnAfterRenderAsync 生命周期方法中安全地运行互操作代码。

但是,由于它在渲染周期之后运行,因此您需要在异步过程完成后使用 StateHasChanged() 通知您的组件重新渲染:

protected override async Task OnAfterRenderAsync(bool firstRender)
{
    if (firstRender)
    {
        var token = await TokenProvider.GetTokenAsync();
        Branches = await Http.GetJsonAsync<List<BranchDto>>(
            "vip/api/lookup/getbranches",
            new AuthenticationHeaderValue("Bearer", token));

        StateHasChanged();
    }
}

【讨论】: