Net MAUI (Blazor)如何在C#类中注入IJSRuntime并调用JS?
在Razor页面外的C#类中注入IJSRuntime调用JavaScript
问题场景
我想在Razor页面之外的C#类中处理JavaScript逻辑,尝试通过注入IJSRuntime实现,相关代码如下:
自定义服务类
public class InvokeJavaScriptService { private IJSRuntime js; public InvokeJavaScriptService(IJSRuntime js) { this.js = js; } public async Task CallJsFromCSharp() { try { await js.InvokeAsync<object>("invokeJSfromCS"); } catch(Exception ex) { Debug.WriteLine(ex.Message); } } }
服务注册
builder.Services.AddScoped<InvokeJavaScriptService>();
前端JavaScript(index.html)
<script> async function invokeJSfromCS() { var value = "C# Method called from JavaScript with parameter"; // 调用C#方法 DotNet.invokeMethodAsync ('MauiBlazorTestApp', 'JStoCSCall', value); } </script>
Razor页面回调方法(index.razor)
@page "/" <div> </div> @code{ private static string content { get; set; } [JSInvokable] // 接收JavaScript回调的C#方法 public static void JStoCSCall(string value) { content = value; } }
调用CallJsFromCSharp()时出现错误,但预期是触发index.html中的invokeJSfromCS函数并回调到Razor页面的方法。既然Razor页面可以通过@inject注入IJSRuntime,那C#类中应该也可以实现,请问该怎么做?
解决方案
1. 确认上下文有效性
IJSRuntime仅在Blazor渲染上下文内有效,你的InvokeJavaScriptService必须在Blazor组件的生命周期内被注入和调用,不能在非Blazor上下文(比如后台服务、应用启动阶段)直接调用,否则会因JS运行时上下文缺失报错。
2. 在Razor组件中正确调用服务
在需要触发JS逻辑的Razor组件中注入服务,选择合适的生命周期方法(推荐OnAfterRenderAsync,确保组件渲染完成、JS环境就绪)调用服务方法:
@page "/" @inject InvokeJavaScriptService JsService <div> </div> @code{ private static string content { get; set; } protected override async Task OnAfterRenderAsync(bool firstRender) { if (firstRender) { // 组件首次渲染完成后触发JS调用 await JsService.CallJsFromCSharp(); } } [JSInvokable] public static void JStoCSCall(string value) { content = value; } }
3. 修复JS调用C#的潜在问题
- 确保
DotNet.invokeMethodAsync中的程序集名称'MauiBlazorTestApp'与项目实际程序集名称完全一致(可通过右键项目→属性查看)。 - 静态回调方法无法直接更新组件UI,若需要更新UI,建议改为实例方法并传递组件引用:
修改Razor页面代码:
@page "/" @inject InvokeJavaScriptService JsService @implements IAsyncDisposable <div>@content</div> @code{ private string content { get; set; } private DotNetObjectReference<Index>? _objRef; protected override async Task OnAfterRenderAsync(bool firstRender) { if (firstRender) { _objRef = DotNetObjectReference.Create(this); // 传递组件引用给JS await JsService.CallJsFromCSharp(_objRef); } } [JSInvokable] public void JStoCSCall(string value) { content = value; StateHasChanged(); // 触发UI更新 } public async ValueTask DisposeAsync() { _objRef?.Dispose(); } }
修改服务类和JS代码:
public class InvokeJavaScriptService { private readonly IJSRuntime _js; public InvokeJavaScriptService(IJSRuntime js) { _js = js; } public async Task CallJsFromCSharp(DotNetObjectReference<Index> objRef) { try { await _js.InvokeAsync<object>("invokeJSfromCS", objRef); } catch(Exception ex) { Debug.WriteLine(ex.Message); } } }
<script> async function invokeJSfromCS(dotNetRef) { var value = "C# Method called from JavaScript with parameter"; // 调用组件实例方法 await dotNetRef.invokeMethodAsync('JStoCSCall', value); } </script>
4. 确认服务注册范围
IJSRuntime本身是Scoped服务,因此你的InvokeJavaScriptService注册为Scoped是正确的,不要注册为Singleton,否则会导致上下文不一致问题。
内容的提问来源于stack exchange,提问作者Razvan Emil
相关产品推荐
相关产品推荐

