NET8 Blazor Web App中localStorage getItem报IJSInProcessRuntime不可用错误
问题背景
将.NET6的Blazor托管Web应用升级为.NET8的Blazor Web App后,能成功设置localStorage中的项,但获取时触发IJSInProcessRuntime not available错误。尝试过将获取逻辑放在OnAfterRenderAsync、切换渲染模式(含/不含预渲染)均无效;已按微软文档将SET逻辑移至MyAssemblyName.lib.module.js,尝试让eventArgsCreator异步返回数据导致应用崩溃。Program.cs已添加builder.Services.AddBlazoredLocalStorage();。
核心问题分析
错误根源是Interactive Server渲染模式下,ISyncLocalStorageService依赖的IJSInProcessRuntime不可用——该模式下Blazor通过SignalR与浏览器通信,仅支持异步JS交互,同步API无法工作。另外,JS中的funcLocal是异步函数但未被await,可能导致Blazor尝试获取数据时,localStorage还未完成写入。
修复步骤
1. 替换同步LocalStorage服务为异步版本
将页面中的ISyncLocalStorageService替换为ILocalStorageService,使用异步方法获取数据:
@page "/stackoverflow" @inject IJSRuntime JS @inject Blazored.LocalStorage.ILocalStorageService localStorage <!-- 替换为异步服务 --> @rendermode @(new InteractiveServerRenderMode(prerender: false)) @if (GetImageBool && !string.IsNullOrEmpty(Image)) { @Image <img src="@Image" /> } <input id="textarea" Title="右键从截图工具粘贴图片" @onpastemultimedia="HandlePasteMultimedia" class="pasteimagearea" style=@($"visibility:{(SavingImage ? "hidden" : "visible")}") /> <style> .pasteimagearea { background: url(images/PASTEIMAGE.png) center center no-repeat; width: 50vw; height: 50vh; } </style> @code { public bool SavingImage { get; set; } = false; public string Image { get; set; } = ""; private bool GetImageBool { get; set; } = false; protected override async Task OnAfterRenderAsync(bool firstRender) { if (GetImageBool) { // 使用异步方法获取数据 var thisvar = await localStorage.GetItemAsStringAsync("thisimage"); Image = thisvar; // 重置标记避免重复执行 GetImageBool = false; StateHasChanged(); } } public async Task HandlePasteMultimedia(PasteMultimediaEventArgs e) { SavingImage = true; GetImageBool = true; StateHasChanged(); } }
2. 修正JS中异步写入localStorage的时序问题
当前eventArgsCreator调用funcLocal时未await,导致Blazor触发获取逻辑时,localStorage可能还未完成写入。修改JS代码,让自定义事件等待写入完成后再通知Blazor:
blazor.registerCustomEventType('pastemultimedia', { browserEventName: 'paste', createEventArgs: async (event) => { // 改为async函数 console.log("In processPasteEvent"); const items = event.clipboardData.items; const acceptedMediaTypes = ["image/png"]; let isMultimedia = false; let data = null; let file = null; for (let i = 0; i < items.length; i++) { file = items[i].getAsFile(); if (!file) continue; if (!items[i].type.includes('image')) continue; if (acceptedMediaTypes.indexOf(items[i].type) === -1) continue; isMultimedia = true; data = URL.createObjectURL(file); await funcLocal(file); // await异步写入操作 break; } return { IsMultimedia: isMultimedia, Data: data }; } }); async function funcLocal(fileParam) { const result = await blobToBase64(fileParam); console.log(`Saving to local storage: ${result.substring(0, 100)}`); localStorage.setItem("thisimage", result); return result; } // 补充blobToBase64转换函数(若之前未定义) function blobToBase64(blob) { return new Promise((resolve, reject) => { const reader = new FileReader(); reader.onloadend = () => resolve(reader.result); reader.onerror = reject; reader.readAsDataURL(blob); }); }
注:Blazor自定义事件支持async的
createEventArgs函数,只要返回Promise即可,之前的崩溃大概率是未正确处理Promise或缺少blobToBase64定义导致。
3. 确认Program.cs配置正确
确保Program.cs中针对Interactive Server模式的服务注册正确:
// Program.cs builder.Services.AddBlazoredLocalStorage(); // Web App模式下需添加交互服务 builder.Services.AddRazorComponents() .AddInteractiveServerComponents();
原错误信息
[2024-07-15T14:00:19.626Z] Error: System.AggregateException: One or more errors occurred. (IJSInProcessRuntime not available) ---> System.InvalidOperationException: IJSInProcessRuntime not available at Blazored.LocalStorage.BrowserStorageProvider.CheckForInProcessRuntime() at Blazored.LocalStorage.BrowserStorageProvider.GetItem(String key) at Blazored.LocalStorage.LocalStorageService.GetItemAsString(String key) at MyAssemblyName.Client.Pages.StackOverflowComponent.OnAfterRenderAsync(Boolean firstRender) in C:\MyAssemblyName\MyAssemblyName.Client\Pages\StackOverflowComponent.razor:line 48
自定义事件定义(无需修改)
public class PasteMultimediaEventArgs : EventArgs { public bool IsMultimedia { get; set; } public string? Data { get; set; } } [EventHandler("onpastemultimedia", typeof(PasteMultimediaEventArgs), enableStopPropagation: true, enablePreventDefault: true)] public static class EventHandlers { }
内容的提问来源于stack exchange,提问作者user13814551

