diff --git a/src/BootstrapBlazor.Server/Components/Samples/JSRuntimeExtensions.razor.cs b/src/BootstrapBlazor.Server/Components/Samples/JSRuntimeExtensions.razor.cs index 58e472cafad..c6ee8fdab2f 100644 --- a/src/BootstrapBlazor.Server/Components/Samples/JSRuntimeExtensions.razor.cs +++ b/src/BootstrapBlazor.Server/Components/Samples/JSRuntimeExtensions.razor.cs @@ -39,7 +39,7 @@ protected override async Task OnAfterRenderAsync(bool firstRender) private async Task OpenUrl_Self() => await Module.OpenUrl(Url, "_self"); - private bool IsMobile { get; set; } + private bool? IsMobile { get; set; } private async Task GetIsMobile() => IsMobile = await Module.IsMobile(); @@ -49,9 +49,9 @@ protected override async Task OnAfterRenderAsync(bool firstRender) `当前URL: ${currentUrl}`; """; - private string evalResult { get; set; } = string.Empty; + private string? evalResult { get; set; } - private async Task RunEval() => evalResult = await Module.Eval(evalContent); + private async Task RunEval() => evalResult = await Module.Eval(evalContent); private string functionContent = """ const currentUrl = window.location.href; @@ -59,9 +59,9 @@ protected override async Task OnAfterRenderAsync(bool firstRender) return `当前URL: ${currentUrl}`; """; - private string functionResult { get; set; } = string.Empty; + private string? functionResult { get; set; } - private async Task RunFunction() => functionResult = await Module.Function(functionContent); + private async Task RunFunction() => functionResult = await Module.Function(functionContent); private MethodItem[] GetMethods() => [ diff --git a/src/BootstrapBlazor/Components/WebSpeech/Synthesizer/WebSpeechSynthesizer.cs b/src/BootstrapBlazor/Components/WebSpeech/Synthesizer/WebSpeechSynthesizer.cs index 2233f65d619..92b93b97012 100644 --- a/src/BootstrapBlazor/Components/WebSpeech/Synthesizer/WebSpeechSynthesizer.cs +++ b/src/BootstrapBlazor/Components/WebSpeech/Synthesizer/WebSpeechSynthesizer.cs @@ -27,7 +27,7 @@ public class WebSpeechSynthesizer(JSModule module, IComponentIdGenerator compone /// 获得 语音包方法 /// /// - public async Task GetVoices() => await module.InvokeAsync("getVoices"); + public async Task GetVoices() => await module.InvokeAsync("getVoices"); /// /// 开始朗读方法 diff --git a/src/BootstrapBlazor/Extensions/JSModuleExtensions.cs b/src/BootstrapBlazor/Extensions/JSModuleExtensions.cs index 95cf05f33f1..8b10b852a72 100644 --- a/src/BootstrapBlazor/Extensions/JSModuleExtensions.cs +++ b/src/BootstrapBlazor/Extensions/JSModuleExtensions.cs @@ -25,6 +25,7 @@ public static class JSModuleExtensions /// A ]]> 模块加载器 public static async Task LoadModule(this IJSRuntime jsRuntime, string fileName, string? version = null) { + JSModule? module = null; if (!string.IsNullOrEmpty(version)) { fileName = $"{fileName}?v={version}"; @@ -32,12 +33,10 @@ public static async Task LoadModule(this IJSRuntime jsRuntime, string try { var jSObjectReference = await jsRuntime.InvokeAsync(identifier: "import", fileName); - return new JSModule(jSObjectReference); - } - catch (Exception ex) - { - throw new Exception($"load {fileName} module fail", ex); + module = new JSModule(jSObjectReference); } + catch (OperationCanceledException) { } + return module ?? new JSModule(null); } /// @@ -80,7 +79,7 @@ public static string GetTypeModuleName(this Type type) /// 实例 /// /// A that represents the asynchronous invocation operation. - public static ValueTask Eval(this JSModule module, string script) => module.InvokeAsync("runEval", script); + public static ValueTask Eval(this JSModule module, string script) => module.InvokeAsync("runEval", script); /// /// 通过 Function 动态运行 JavaScript 代码 @@ -94,80 +93,20 @@ public static string GetTypeModuleName(this Type type) /// /// 动态运行js代码 /// - /// + /// /// 实例 /// /// /// A that represents the asynchronous invocation operation. - public static ValueTask Function(this JSModule module, string script, params object?[]? args) => module.InvokeAsync("runFunction", script, args); - - ///// - ///// 动态增加 head 标签 - ///// - ///// 示例: - ///// - ///// [Inject] - ///// [NotNull] - ///// private JSRuntime - ///// - ///// [NotNull] - ///// private ? Module { get; set; } - ///// - ///// protected override OnAfterRenderAsync(bool firstRender) - ///// { - ///// .OnAfterRenderAsync(firstRender); - ///// - ///// (firstRender) - ///// { - ///// Module = JSRuntime.LoadUtility(); - ///// } - ///// } - ///// - ///// private OnClick() - ///// { - ///// var result = Module.AddMetaAsync("styles.css") - ///// } - ///// - ///// - ///// - ///// 实例 - ///// 添加的 Meta 内容 - ///// A that represents the asynchronous invocation operation. - //public static ValueTask AddMetaAsync(this JSModule module, string content) => module.InvokeAsync("addMeta", content); - - ///// - ///// 动态移除 head 标签 - ///// - ///// 示例: - ///// - ///// [Inject] - ///// [NotNull] - ///// private JSRuntime - ///// - ///// [NotNull] - ///// private ? Module { get; set; } - ///// - ///// protected override OnAfterRenderAsync(bool firstRender) - ///// { - ///// .OnAfterRenderAsync(firstRender); - ///// - ///// (firstRender) - ///// { - ///// Module = JSRuntime.LoadUtility(); - ///// } - ///// } - ///// - ///// private OnClick() - ///// { - ///// var result = Module.RemoveMetaAsync("styles.css") - ///// } - ///// - ///// - ///// - ///// 实例 - ///// 移除 Meta 内容 - ///// A that represents the asynchronous invocation operation. - //public static ValueTask RemoveMetaAsync(this JSModule module, string content) => module.InvokeAsync("removeMeta", content); + public static async ValueTask Function(this JSModule module, string script, params object?[]? args) + { + TValue? ret = default; + if (module != null) + { + ret = await module.InvokeAsync("runFunction", script, args); + } + return ret; + } /// /// 获取当前终端是否为移动设备 diff --git a/src/BootstrapBlazor/Utils/JSModule.cs b/src/BootstrapBlazor/Utils/JSModule.cs index 4bb970b7710..298e698e8c0 100644 --- a/src/BootstrapBlazor/Utils/JSModule.cs +++ b/src/BootstrapBlazor/Utils/JSModule.cs @@ -10,12 +10,6 @@ namespace BootstrapBlazor.Components; /// public class JSModule(IJSObjectReference? jSObjectReference) : IAsyncDisposable { - /// - /// IJSObjectReference 实例 - /// - [NotNull] - private IJSObjectReference? Module { get; } = jSObjectReference ?? throw new ArgumentNullException(nameof(jSObjectReference)); - /// /// InvokeVoidAsync 方法 /// @@ -58,7 +52,10 @@ async ValueTask InvokeVoidAsync() { try { - await Module.InvokeVoidAsync(identifier, cancellationToken, [.. paras]); + if (jSObjectReference != null) + { + await jSObjectReference.InvokeVoidAsync(identifier, cancellationToken, [.. paras]); + } } catch (JSException) { @@ -79,7 +76,7 @@ async ValueTask InvokeVoidAsync() /// /// /// - public virtual ValueTask InvokeAsync(string identifier, params object?[]? args) => InvokeAsync(identifier, CancellationToken.None, args); + public virtual ValueTask InvokeAsync(string identifier, params object?[]? args) => InvokeAsync(identifier, CancellationToken.None, args); /// /// InvokeAsync 方法 @@ -88,11 +85,11 @@ async ValueTask InvokeVoidAsync() /// /// /// - public virtual ValueTask InvokeAsync(string identifier, TimeSpan timeout, params object?[]? args) + public virtual ValueTask InvokeAsync(string identifier, TimeSpan timeout, params object?[]? args) { using CancellationTokenSource? cancellationTokenSource = ((timeout == Timeout.InfiniteTimeSpan) ? null : new CancellationTokenSource(timeout)); CancellationToken cancellationToken = cancellationTokenSource?.Token ?? CancellationToken.None; - return InvokeAsync(identifier, cancellationToken, args); + return InvokeAsync(identifier, cancellationToken, args); } /// @@ -102,7 +99,7 @@ public virtual ValueTask InvokeAsync(string identifier, TimeSpan /// /// /// - public virtual async ValueTask InvokeAsync(string identifier, CancellationToken cancellationToken = default, params object?[]? args) + public virtual async ValueTask InvokeAsync(string identifier, CancellationToken cancellationToken = default, params object?[]? args) { var paras = new List(); if (args != null) @@ -111,12 +108,15 @@ public virtual async ValueTask InvokeAsync(string identifier, Ca } return await InvokeAsync(); - async ValueTask InvokeAsync() + async ValueTask InvokeAsync() { - TValue ret = default!; + TValue? ret = default; try { - ret = await Module.InvokeAsync(identifier, cancellationToken, [.. paras]); + if (jSObjectReference != null) + { + ret = await jSObjectReference.InvokeAsync(identifier, cancellationToken, [.. paras]); + } } catch (JSException) { @@ -143,7 +143,10 @@ protected virtual async ValueTask DisposeAsyncCore(bool disposing) { try { - await Module.DisposeAsync(); + if (jSObjectReference != null) + { + await jSObjectReference.DisposeAsync(); + } } catch { } } diff --git a/test/UnitTest/Extensions/JSModuleExtensionsTest.cs b/test/UnitTest/Extensions/JSModuleExtensionsTest.cs index 1ab0381cc66..1a59319f123 100644 --- a/test/UnitTest/Extensions/JSModuleExtensionsTest.cs +++ b/test/UnitTest/Extensions/JSModuleExtensionsTest.cs @@ -19,8 +19,8 @@ public async Task LoadModule_Ok() public async Task LoadModule_Exception() { var jsRuntime = new MockJSRuntime(); - var ex = await Assert.ThrowsAsync(async () => await jsRuntime.LoadModule("./mock.js", "test")); - Assert.Equal("load ./mock.js?v=test module fail", ex.Message); + var module = await jsRuntime.LoadModule("./mock.js", "test"); + Assert.NotNull(module); } [Fact] @@ -98,12 +98,12 @@ class MockJSRuntime : IJSRuntime { public ValueTask InvokeAsync<[DynamicallyAccessedMembers(DynamicallyAccessedMemberTypes.PublicConstructors | DynamicallyAccessedMemberTypes.PublicFields | DynamicallyAccessedMemberTypes.PublicProperties)] TValue>(string identifier, object?[]? args) { - throw new NotImplementedException(); + throw new TaskCanceledException(); } public ValueTask InvokeAsync<[DynamicallyAccessedMembers(DynamicallyAccessedMemberTypes.PublicConstructors | DynamicallyAccessedMemberTypes.PublicFields | DynamicallyAccessedMemberTypes.PublicProperties)] TValue>(string identifier, CancellationToken cancellationToken, object?[]? args) { - throw new NotImplementedException(); + throw new TaskCanceledException(); } } } diff --git a/test/UnitTest/Services/WebSpeechSynthesizerTest.cs b/test/UnitTest/Services/WebSpeechSynthesizerTest.cs index 55fc1d7de4e..503132baa65 100644 --- a/test/UnitTest/Services/WebSpeechSynthesizerTest.cs +++ b/test/UnitTest/Services/WebSpeechSynthesizerTest.cs @@ -79,7 +79,7 @@ public async Task GetVoices_Ok() { var service = Context.Services.GetRequiredService(); var synthesizer = await service.CreateSynthesizerAsync(); - var voices = await synthesizer.GetVoices(); + await synthesizer.GetVoices(); } [Fact] diff --git a/test/UnitTest/Utils/JSModuleTest.cs b/test/UnitTest/Utils/JSModuleTest.cs index c350e176751..d919e728751 100644 --- a/test/UnitTest/Utils/JSModuleTest.cs +++ b/test/UnitTest/Utils/JSModuleTest.cs @@ -14,8 +14,6 @@ public void JSModule_Error() var js = new MockJSObjectReference(); var module = new JSModule(js); Assert.NotNull(module); - - Assert.Throws(() => new JSModule(null)); } [Fact]