调用可能返回null的JS函数时,如何获取IJSObjectReference?
问题解决:处理Blazor中JS函数返回null时的IJSObjectReference异常
问题场景
我有如下TypeScript模块:
export function getIndexedDb() : IDBFactory | null { if (window.indexedDB) return window.indexedDB; else return null; }
想要在C#中获取该函数返回结果的IJSObjectReference,尝试了以下代码:
await using var module = await jsRuntime.InvokeAsync<IJSObjectReference>("import", "xxxx.js"); await using var result = await module.InvokeAsync<IJSObjectReference>("getIndexedDb");
当window.indexedDB存在时代码运行正常,但当getIndexedDb()返回null时会报错:
Uncaught (in promise) Error: Cannot create a JSObjectReference from the value 'null'.
而且C#中无法捕获该异常,方法会直接停止执行后续代码,这是bug吗?另外我觉得用包装类的方案不够简洁:
class Nullable<T> { value: T | null; constructor(value: T | null) { this.value = value; } getValue() : T | null { return this.value; } isNull() : boolean { return this.value === null; } } export function getIndexedDb() : Nullable<IDBFactory> { if (window.indexedDB) return new Nullable<IDBFactory>(window.indexedDB); else return new Nullable<IDBFactory>(null); }
解决方法
方法1:拆分判断与获取逻辑
在TS中新增判断函数,先确认IndexedDB是否存在,再安全获取实例:
// TS代码 export function hasIndexedDb(): boolean { return !!window.indexedDB; } export function getIndexedDb(): IDBFactory { return window.indexedDB!; }
C#中先判断状态,再获取引用:
await using var module = await jsRuntime.InvokeAsync<IJSObjectReference>("import", "xxxx.js"); var hasDb = await module.InvokeAsync<bool>("hasIndexedDb"); if (hasDb) { await using var dbInstance = await module.InvokeAsync<IJSObjectReference>("getIndexedDb"); // 在这里使用dbInstance操作IndexedDB }
方法2:返回包含状态的普通对象
修改TS函数返回包含存在状态和实例的普通对象,无需额外包装类:
// TS代码 export function getIndexedDb(): { exists: boolean, instance?: IDBFactory } { if (window.indexedDB) { return { exists: true, instance: window.indexedDB }; } else { return { exists: false }; } }
C#中定义对应实体类并处理:
// 定义C#实体类 public class IndexedDbResponse { public bool Exists { get; set; } } // 调用代码 await using var module = await jsRuntime.InvokeAsync<IJSObjectReference>("import", "xxxx.js"); var response = await module.InvokeAsync<IndexedDbResponse>("getIndexedDb"); if (response.Exists) { var dbInstance = await module.InvokeAsync<IJSObjectReference>("getIndexedDb"); // 使用实例 }
方法3:通过object类型中转避免异常
在C#中先以object类型接收返回值,再判断是否为IJSObjectReference:
await using var module = await jsRuntime.InvokeAsync<IJSObjectReference>("import", "xxxx.js"); var resultObj = await module.InvokeAsync<object>("getIndexedDb"); if (resultObj is IJSObjectReference dbInstance) { // 使用dbInstance } else { // 处理null情况,比如提示不支持IndexedDB }
关于异常无法捕获的问题
这不是bug,因为JS端抛出的Promise异常发生在JS线程,Blazor的.NET代码无法直接捕获未处理的JS Promise异常。要避免这种情况,要么在JS层确保不会抛出异常(比如上述方案),要么在JS中用try-catch包裹逻辑并返回错误状态,而不是抛出异常。
内容的提问来源于stack exchange,提问作者yueyinqiu
相关产品推荐
相关产品推荐

