ABP框架Blazor WASM JS互操作报UnsupportedJavaScriptRuntime错误
错误根源
ABP框架默认生成的Blazor WebAssembly项目模板开启了**服务器端预渲染(Prerendering)**流程。这个阶段组件会在服务端先行执行一遍生成静态HTML,此时页面还没有在浏览器完成加载,框架注入的IJSRuntime是专门用来拦截JS互操作调用的UnsupportedJavaScriptRuntime占位实例,所有依赖浏览器环境的localStorage读写操作自然会触发报错。
你之前在普通Blazor Server项目能正常跑通的逻辑,是因为默认项目模板没有开启这类预渲染流程,注入的JS运行时是基于SignalR连接的正常可用实例,自然不会触发这个拦截。
解决方法
- 方案1:给所有JS互操作调用加前置判断,直接跳过预渲染阶段的执行
在调用InvokeAsync之前先判断当前运行时是否支持进程内JS调用,预渲染阶段直接返回空实例,等浏览器加载完成后再走真实业务逻辑:private async Task<Order> GetOrder() { // 预渲染阶段无可用JS运行时,直接返回空对象 if (_jSRuntime is not IJSInProcessRuntime) { return new Order(); } // 以下为原有业务逻辑 Order order = null; var strOrder = await _jSRuntime.InvokeAsync<string>("localStorage.getItem", cstrShoppingCart); if (!string.IsNullOrWhiteSpace(strOrder) && strOrder.ToLower() != "null") order = JsonConvert.DeserializeObject<Order>(strOrder); else { order = new Order(); await SetOrder(order); } foreach(var item in order.LineItems) { item.Product = await _productRepository.GetAsync(item.ProductId); } return order; } - 方案2:调整JS互操作逻辑的触发时机
把涉及JS互操作的逻辑从OnInitializedAsync等会被预渲染触发的生命周期方法,移到OnAfterRenderAsync的首次渲染回调里,这个时机已经是浏览器端完成JS运行时初始化的阶段,不会触发预渲染拦截:protected override async Task OnAfterRenderAsync(bool firstRender) { if (firstRender) { CurrentOrder = await GetOrder(); StateHasChanged(); } } - 方案3:关闭预渲染流程
如果业务上不需要预渲染带来的首屏提速效果,可以直接在WebAssembly项目的启动配置里关闭预渲染中间件,所有组件会直接在浏览器端执行初始渲染,原有代码逻辑不需要修改即可正常运行。
注意:ABP框架自带的本地存储、缓存等依赖浏览器JS环境的服务,同样存在预渲染阶段的调用拦截问题,套用上述判断逻辑即可兼容。
内容的提问来源于stack exchange,提问作者Jad
相关产品推荐
相关产品推荐

